From 6b1ae88e242cc94631b01b47ae4f3cc3262f3f5a Mon Sep 17 00:00:00 2001 From: Oliver Egger Date: Tue, 8 Sep 2020 09:27:32 +0200 Subject: [PATCH 01/73] add patch wildcard for ig depencies --- .../hl7/fhir/utilities/VersionUtilities.java | 38 ++++++++++++++++++- .../cache/BasePackageCacheManager.java | 3 ++ .../cache/FilesystemPackageCacheManager.java | 15 +++++++- .../fhir/utilities/cache/PackageClient.java | 14 +++++++ .../hl7/fhir/validation/ValidationEngine.java | 12 ++++++ 5 files changed, 80 insertions(+), 2 deletions(-) diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/VersionUtilities.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/VersionUtilities.java index 3b303a035..91e8d46b2 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/VersionUtilities.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/VersionUtilities.java @@ -193,6 +193,16 @@ public class VersionUtilities { } } + public static String getPatch(String version) { + if (version == null) + return null; + if (Utilities.charCount(version, '.') == 2) { + String[] p = version.split("\\."); + return p[2]; + } + return null; + } + public static boolean isSemVer(String version) { if (Utilities.charCount(version, '.') != 2) { return false; @@ -202,7 +212,7 @@ public class VersionUtilities { } /** - * return true if the current vresion equals test, or later + * return true if the current version equals test, or later * * so if a feature is defined in 4.0, if (VersionUtilities.isThisOrLater("4.0", version))... * @@ -213,10 +223,36 @@ public class VersionUtilities { public static boolean isThisOrLater(String test, String current) { String t = getMajMin(test); String c = getMajMin(current); + if (c.compareTo(t) == 0) { + return isMajMinOrLaterPatch(test, current); + } boolean ok = c.compareTo(t) >= 0; return ok; } + /** + * return true if the current version equals test for major and min, or later patch + * + * @param test + * @param current + * @return + */ + public static boolean isMajMinOrLaterPatch(String test, String current) { + String t = getMajMin(test); + String c = getMajMin(current); + if (c.compareTo(t) == 0) { + String pt = getPatch(test); + String pc = getPatch(current); + if (pt==null || "x".equals(pt)) { + return true; + } + if (pc!=null) { + return pc.compareTo(pt) >= 0; + } + } + return false; + } + public static String incMajorVersion(String v) { assert isSemVer(v); int[] parts = splitParts(v); diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/BasePackageCacheManager.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/BasePackageCacheManager.java index 82e295e89..5074396bd 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/BasePackageCacheManager.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/BasePackageCacheManager.java @@ -69,6 +69,9 @@ public abstract class BasePackageCacheManager implements IPackageCacheManager { if (Utilities.noString(version)) { version = packageClient.getLatestVersion(id); } + if (version.endsWith(".x")) { + version = packageClient.getLatestVersion(id, version); + } InputStream stream = packageClient.fetch(id, version); String url = packageClient.url(id, version); return new InputStreamWithSrc(stream, url, version); diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/FilesystemPackageCacheManager.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/FilesystemPackageCacheManager.java index bf9bdac65..4415901af 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/FilesystemPackageCacheManager.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/FilesystemPackageCacheManager.java @@ -39,6 +39,7 @@ import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.utilities.IniFile; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; +import org.hl7.fhir.utilities.VersionUtilities; import org.hl7.fhir.utilities.cache.NpmPackage.NpmPackageFolder; import org.hl7.fhir.utilities.json.JSONUtil; import org.slf4j.Logger; @@ -283,7 +284,7 @@ public class FilesystemPackageCacheManager extends BasePackageCacheManager imple } /** - * Load the identified package from the cache - it it exists + * Load the identified package from the cache - if it exists *

* This is for special purpose only (testing, control over speed of loading). * Generally, use the loadPackage method @@ -307,10 +308,22 @@ public class FilesystemPackageCacheManager extends BasePackageCacheManager imple return p; } } + String foundPackage = null; + String foundVersion = null; for (String f : sorted(new File(cacheFolder).list())) { if (f.equals(id + "#" + version) || (Utilities.noString(version) && f.startsWith(id + "#"))) { return loadPackageInfo(Utilities.path(cacheFolder, f)); } + if (version!=null && version.endsWith(".x") && f.contains("#")) { + String[] parts = f.split("#"); + if (parts[0].equals(id) && VersionUtilities.isMajMinOrLaterPatch((foundVersion!=null ? foundVersion : version),parts[1])) { + foundVersion = parts[1]; + foundPackage = f; + } + } + } + if (foundPackage!=null) { + return loadPackageInfo(Utilities.path(cacheFolder, foundPackage)); } if ("dev".equals(version)) return loadPackageFromCacheOnly(id, "current"); diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/PackageClient.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/PackageClient.java index f384d2f2e..7171bf548 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/PackageClient.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/PackageClient.java @@ -208,5 +208,19 @@ public class PackageClient { } } + public String getLatestVersion(String id, String majMinVersion) throws IOException { + List list = getVersions(id); + if (list.isEmpty()) { + throw new IOException("Package not found: "+id); + } else { + String v = majMinVersion; + for (PackageInfo p : list) { + if (VersionUtilities.isMajMinOrLaterPatch(v, p.version)) { + v = p.version; + } + } + return v; + } + } } \ No newline at end of file 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 b6ca6b9f2..d01ed9700 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 @@ -762,6 +762,18 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst context.getLoadedPackages().add(pi.name()+"#"+pi.version()); Map res = new HashMap(); for (String s : pi.dependencies()) { + if (s.endsWith(".x") && s.length()>2) { + String packageMajorMinor = s.substring(0, s.length()-2); + boolean found = false; + for (int i=0; i Date: Wed, 16 Sep 2020 13:08:02 +1000 Subject: [PATCH 02/73] FHIRPath - support lenient mode on polymorphics --- RELEASE_NOTES.md | 5 + .../org/hl7/fhir/r5/utils/FHIRPathEngine.java | 29 +++- .../org/hl7/fhir/r5/test/FHIRPathTests.java | 149 +++++++++++------- pom.xml | 2 +- 4 files changed, 125 insertions(+), 60 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index e69de29bb..c8185536a 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -0,0 +1,5 @@ +Validator: +* No changes + +Other code changes: +* Support lenient mode on FIHRPath when referring to polymorphics diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java index e7a7f33a2..609e4ffec 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java @@ -105,6 +105,7 @@ import ca.uhn.fhir.util.ElementUtil; * */ public class FHIRPathEngine { + private enum Equality { Null, True, False } private class FHIRConstant extends Base { @@ -211,6 +212,7 @@ public class FHIRPathEngine { private ValidationOptions terminologyServiceOptions = new ValidationOptions(); private ProfileUtilities profileUtilities; private String location; // for error messages + private boolean allowPolymorphicNames; // if the fhir path expressions are allowed to use constants beyond those defined in the specification // the application can implement them by providing a constant resolver @@ -372,10 +374,24 @@ public class FHIRPathEngine { * @throws FHIRException */ protected void getChildrenByName(Base item, String name, List result) throws FHIRException { + String tn = null; + if (isAllowPolymorphicNames()) { + // we'll look to see whether we hav a polymorphic name + for (Property p : item.children()) { + if (p.getName().endsWith("[x]")) { + String n = p.getName().substring(0, p.getName().length()-3); + if (name.startsWith(n)) { + tn = name.substring(n.length()); + name = n; + break; + } + } + } + } Base[] list = item.listChildrenByName(name, false); if (list != null) { for (Base v : list) { - if (v != null) { + if (v != null && (tn == null || v.fhirType().equalsIgnoreCase(tn))) { result.add(v); } } @@ -5166,7 +5182,7 @@ public class FHIRPathEngine { } else { path = sdi.getSnapshot().getElement().get(0).getPath()+tail+"."+name; - ElementDefinitionMatch ed = getElementDefinition(sdi, path, false); + ElementDefinitionMatch ed = getElementDefinition(sdi, path, isAllowPolymorphicNames()); if (ed != null) { if (!Utilities.noString(ed.getFixedType())) result.addType(ed.getFixedType()); @@ -5556,5 +5572,14 @@ public class FHIRPathEngine { public IWorkerContext getWorker() { return worker; } + + public boolean isAllowPolymorphicNames() { + return allowPolymorphicNames; + } + + public void setAllowPolymorphicNames(boolean allowPolymorphicNames) { + this.allowPolymorphicNames = allowPolymorphicNames; + } + } \ No newline at end of file diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/FHIRPathTests.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/FHIRPathTests.java index 3aac680b5..108ea465a 100644 --- a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/FHIRPathTests.java +++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/FHIRPathTests.java @@ -24,6 +24,7 @@ import org.hl7.fhir.r5.model.Quantity; import org.hl7.fhir.r5.model.Resource; import org.hl7.fhir.r5.model.TypeDetails; import org.hl7.fhir.r5.model.ValueSet; +import org.hl7.fhir.r5.test.FHIRPathTests.TestResultType; import org.hl7.fhir.r5.test.utils.TestingUtilities; import org.hl7.fhir.r5.utils.FHIRPathEngine; import org.hl7.fhir.r5.utils.FHIRPathEngine.IEvaluationContext; @@ -41,6 +42,8 @@ import org.xml.sax.SAXException; public class FHIRPathTests { + public enum TestResultType {OK, SYNTAX, SEMANTICS, EXECUTION} + public class FHIRPathTestEvaluationServices implements IEvaluationContext { @Override @@ -111,6 +114,7 @@ public class FHIRPathTests { XMLUtil.getNamedChildren(dom.getDocumentElement(), "group", groups); for (Element g : groups) { XMLUtil.getNamedChildren(g, "test", list); + XMLUtil.getNamedChildren(g, "modeTest", list); } List objects = new ArrayList<>(); @@ -147,84 +151,115 @@ public class FHIRPathTests { public void test(String name, Element test) throws FileNotFoundException, IOException, FHIRException, org.hl7.fhir.exceptions.FHIRException, UcumException { // Setting timezone for this test. Grahame is in UTC+11, Travis is in GMT, and I'm here in Toronto, Canada with // all my time based tests failing locally... - TimeZone.setDefault(TimeZone.getTimeZone("UTC+1100")); + TimeZone.setDefault(TimeZone.getTimeZone("UTC+1100")); fp.setHostServices(new FHIRPathTestEvaluationServices()); String input = test.getAttribute("inputfile"); String expression = XMLUtil.getNamedChild(test, "expression").getTextContent(); - boolean fail = Utilities.existsInList(XMLUtil.getNamedChild(test, "expression").getAttribute("invalid"), "true", "semantic"); + TestResultType fail = TestResultType.OK; + if ("syntax".equals(XMLUtil.getNamedChild(test, "expression").getAttribute("invalid"))) { + fail = TestResultType.SYNTAX; + } else if ("semantic".equals(XMLUtil.getNamedChild(test, "expression").getAttribute("invalid"))) { + fail = TestResultType.SEMANTICS; + } else if ("execution".equals(XMLUtil.getNamedChild(test, "expression").getAttribute("invalid"))) { + fail = TestResultType.EXECUTION; + }; + fp.setAllowPolymorphicNames("lenient/polymorphics".equals(test.getAttribute("mode"))); Resource res = null; List outcome = new ArrayList(); - ExpressionNode node = fp.parse(expression); + System.out.println(name); + + ExpressionNode node = null; try { - if (Utilities.noString(input)) { - fp.check(null, null, node); - } else { - res = resources.get(input); - if (res == null) { - res = new XmlParser().parse(TestingUtilities.loadTestResourceStream("r5", input)); - resources.put(input, res); - } - fp.check(res, res.getResourceType().toString(), res.getResourceType().toString(), node); - } - outcome = fp.evaluate(res, node); - Assertions.assertFalse(fail, String.format("Expected exception parsing %s", expression)); + node = fp.parse(expression); + Assertions.assertTrue(fail != TestResultType.SYNTAX, String.format("Expected exception didn't occur parsing %s", expression)); } catch (Exception e) { - Assertions.assertTrue(fail, String.format("Unexpected exception parsing %s: " + e.getMessage(), expression)); + Assertions.assertTrue(fail == TestResultType.SYNTAX, String.format("Unexpected exception parsing %s: " + e.getMessage(), expression)); + } + + if (node != null) { + try { + if (Utilities.noString(input)) { + fp.check(null, null, node); + } else { + res = resources.get(input); + if (res == null) { + res = new XmlParser().parse(TestingUtilities.loadTestResourceStream("r5", input)); + resources.put(input, res); + } + fp.check(res, res.getResourceType().toString(), res.getResourceType().toString(), node); + } + Assertions.assertTrue(fail != TestResultType.SEMANTICS, String.format("Expected exception didn't occur checking %s", expression)); + } catch (Exception e) { + Assertions.assertTrue(fail == TestResultType.SEMANTICS, String.format("Unexpected exception checking %s: " + e.getMessage(), expression)); + node = null; + } + } + + if (node != null) { + try { + outcome = fp.evaluate(res, node); + Assertions.assertTrue(fail == TestResultType.OK, String.format("Expected exception didn't occur executing %s", expression)); + } catch (Exception e) { + Assertions.assertTrue(fail == TestResultType.EXECUTION, String.format("Unexpected exception executing %s: " + e.getMessage(), expression)); + node = null; + } } - if ("true".equals(test.getAttribute("predicate"))) { - boolean ok = fp.convertToBoolean(outcome); - outcome.clear(); - outcome.add(new BooleanType(ok)); - } - System.out.println(name); if (fp.hasLog()) { System.out.println(name); System.out.println(fp.takeLog()); } - List expected = new ArrayList(); - XMLUtil.getNamedChildren(test, "output", expected); - Assertions.assertEquals(outcome.size(), expected.size(), String.format("Expected %d objects but found %d for expression %s", expected.size(), outcome.size(), expression)); - if ("false".equals(test.getAttribute("ordered"))) { - for (int i = 0; i < Math.min(outcome.size(), expected.size()); i++) { - String tn = outcome.get(i).fhirType(); - String s; - if (outcome.get(i) instanceof Quantity) { - s = fp.convertToString(outcome.get(i)); - } else { - s = ((PrimitiveType) outcome.get(i)).asStringValue(); - } - boolean found = false; - for (Element e : expected) { - if ((Utilities.noString(e.getAttribute("type")) || e.getAttribute("type").equals(tn)) && - (Utilities.noString(e.getTextContent()) || e.getTextContent().equals(s))) { - found = true; - } - } - Assertions.assertTrue(found, String.format("Outcome %d: Value %s of type %s not expected for %s", i, s, tn, expression)); + if (node != null) { + if ("true".equals(test.getAttribute("predicate"))) { + boolean ok = fp.convertToBoolean(outcome); + outcome.clear(); + outcome.add(new BooleanType(ok)); } - } else { - for (int i = 0; i < Math.min(outcome.size(), expected.size()); i++) { - String tn = expected.get(i).getAttribute("type"); - if (!Utilities.noString(tn)) { - Assertions.assertEquals(tn, outcome.get(i).fhirType(), String.format("Outcome %d: Type should be %s but was %s", i, tn, outcome.get(i).fhirType())); - } - String v = expected.get(i).getTextContent(); - if (!Utilities.noString(v)) { + + List expected = new ArrayList(); + XMLUtil.getNamedChildren(test, "output", expected); + Assertions.assertEquals(outcome.size(), expected.size(), String.format("Expected %d objects but found %d for expression %s", expected.size(), outcome.size(), expression)); + if ("false".equals(test.getAttribute("ordered"))) { + for (int i = 0; i < Math.min(outcome.size(), expected.size()); i++) { + String tn = outcome.get(i).fhirType(); + String s; if (outcome.get(i) instanceof Quantity) { - Quantity q = fp.parseQuantityString(v); - Assertions.assertTrue(outcome.get(i).equalsDeep(q), String.format("Outcome %d: Value should be %s but was %s", i, v, outcome.get(i).toString())); + s = fp.convertToString(outcome.get(i)); } else { - Assertions.assertTrue(outcome.get(i) instanceof PrimitiveType, String.format("Outcome %d: Value should be a primitive type but was %s", i, outcome.get(i).fhirType())); - if (!(v.equals(((PrimitiveType) outcome.get(i)).asStringValue()))) { - System.out.println(name); - System.out.println(String.format("Outcome %d: Value should be %s but was %s for expression %s", i, v, outcome.get(i).toString(), expression)); + s = ((PrimitiveType) outcome.get(i)).asStringValue(); + } + boolean found = false; + for (Element e : expected) { + if ((Utilities.noString(e.getAttribute("type")) || e.getAttribute("type").equals(tn)) && + (Utilities.noString(e.getTextContent()) || e.getTextContent().equals(s))) { + found = true; + } + } + Assertions.assertTrue(found, String.format("Outcome %d: Value %s of type %s not expected for %s", i, s, tn, expression)); + } + } else { + for (int i = 0; i < Math.min(outcome.size(), expected.size()); i++) { + String tn = expected.get(i).getAttribute("type"); + if (!Utilities.noString(tn)) { + Assertions.assertEquals(tn, outcome.get(i).fhirType(), String.format("Outcome %d: Type should be %s but was %s", i, tn, outcome.get(i).fhirType())); + } + String v = expected.get(i).getTextContent(); + if (!Utilities.noString(v)) { + if (outcome.get(i) instanceof Quantity) { + Quantity q = fp.parseQuantityString(v); + Assertions.assertTrue(outcome.get(i).equalsDeep(q), String.format("Outcome %d: Value should be %s but was %s", i, v, outcome.get(i).toString())); + } else { + Assertions.assertTrue(outcome.get(i) instanceof PrimitiveType, String.format("Outcome %d: Value should be a primitive type but was %s", i, outcome.get(i).fhirType())); + if (!(v.equals(((PrimitiveType) outcome.get(i)).asStringValue()))) { + System.out.println(name); + System.out.println(String.format("Outcome %d: Value should be %s but was %s for expression %s", i, v, outcome.get(i).toString(), expression)); + } + Assertions.assertEquals(v, ((PrimitiveType) outcome.get(i)).asStringValue(), String.format("Outcome %d: Value should be %s but was %s for expression %s", i, v, outcome.get(i).toString(), expression)); } - Assertions.assertEquals(v, ((PrimitiveType) outcome.get(i)).asStringValue(), String.format("Outcome %d: Value should be %s but was %s for expression %s", i, v, outcome.get(i).toString(), expression)); } } } diff --git a/pom.xml b/pom.xml index 29be4c280..b2ba8a38e 100644 --- a/pom.xml +++ b/pom.xml @@ -17,7 +17,7 @@ 5.1.0 - 1.1.40 + 1.1.41 5.6.2 3.0.0-M4 0.8.5 From 9b07831809438eeabea6305fa85e4078b5b02030 Mon Sep 17 00:00:00 2001 From: markiantorno Date: Wed, 16 Sep 2020 04:42:16 +0000 Subject: [PATCH 03/73] Release: v5.1.11 Validator: * No changes Other code changes: * Support lenient mode on FIHRPath when referring to polymorphics ***NO_CI*** --- org.hl7.fhir.convertors/pom.xml | 2 +- org.hl7.fhir.dstu2/pom.xml | 2 +- org.hl7.fhir.dstu2016may/pom.xml | 2 +- org.hl7.fhir.dstu3/pom.xml | 2 +- org.hl7.fhir.r4/pom.xml | 2 +- org.hl7.fhir.r5/pom.xml | 2 +- org.hl7.fhir.report/pom.xml | 2 +- org.hl7.fhir.utilities/pom.xml | 2 +- org.hl7.fhir.validation.cli/pom.xml | 2 +- org.hl7.fhir.validation/pom.xml | 2 +- pom.xml | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/org.hl7.fhir.convertors/pom.xml b/org.hl7.fhir.convertors/pom.xml index a2fe5b829..3421ff53d 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 - 5.1.11-SNAPSHOT + 5.1.11 ../pom.xml diff --git a/org.hl7.fhir.dstu2/pom.xml b/org.hl7.fhir.dstu2/pom.xml index 1fffca93b..67e6a8300 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 - 5.1.11-SNAPSHOT + 5.1.11 ../pom.xml diff --git a/org.hl7.fhir.dstu2016may/pom.xml b/org.hl7.fhir.dstu2016may/pom.xml index dabbcf9fa..bf8010cbf 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 - 5.1.11-SNAPSHOT + 5.1.11 ../pom.xml diff --git a/org.hl7.fhir.dstu3/pom.xml b/org.hl7.fhir.dstu3/pom.xml index bb3123f5c..9128c2fdb 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 - 5.1.11-SNAPSHOT + 5.1.11 ../pom.xml diff --git a/org.hl7.fhir.r4/pom.xml b/org.hl7.fhir.r4/pom.xml index 1a88adbb5..0549d92f7 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 - 5.1.11-SNAPSHOT + 5.1.11 ../pom.xml diff --git a/org.hl7.fhir.r5/pom.xml b/org.hl7.fhir.r5/pom.xml index 1af8b5847..7ee278061 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 - 5.1.11-SNAPSHOT + 5.1.11 ../pom.xml diff --git a/org.hl7.fhir.report/pom.xml b/org.hl7.fhir.report/pom.xml index 721217440..9e8858101 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 - 5.1.11-SNAPSHOT + 5.1.11 ../pom.xml diff --git a/org.hl7.fhir.utilities/pom.xml b/org.hl7.fhir.utilities/pom.xml index 07d898511..692b0d690 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 - 5.1.11-SNAPSHOT + 5.1.11 ../pom.xml diff --git a/org.hl7.fhir.validation.cli/pom.xml b/org.hl7.fhir.validation.cli/pom.xml index 07c20fc2f..af3a67c91 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 - 5.1.11-SNAPSHOT + 5.1.11 ../pom.xml diff --git a/org.hl7.fhir.validation/pom.xml b/org.hl7.fhir.validation/pom.xml index db2bc5c32..1d22cb5f3 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 - 5.1.11-SNAPSHOT + 5.1.11 ../pom.xml diff --git a/pom.xml b/pom.xml index b2ba8a38e..5e00c4e16 100644 --- a/pom.xml +++ b/pom.xml @@ -13,7 +13,7 @@ each other. It is fine to bump the point version of this POM without affecting HAPI FHIR. --> - 5.1.11-SNAPSHOT + 5.1.11 5.1.0 From a0573907bd6482e786ad4911f678a87fd4fcbf98 Mon Sep 17 00:00:00 2001 From: markiantorno Date: Wed, 16 Sep 2020 04:59:05 +0000 Subject: [PATCH 04/73] Updating version to: 5.1.12-SNAPSHOT and incrementing test cases dependency. --- RELEASE_NOTES.md | 5 ----- org.hl7.fhir.convertors/pom.xml | 2 +- org.hl7.fhir.dstu2/pom.xml | 2 +- org.hl7.fhir.dstu2016may/pom.xml | 2 +- org.hl7.fhir.dstu3/pom.xml | 2 +- org.hl7.fhir.r4/pom.xml | 2 +- org.hl7.fhir.r5/pom.xml | 2 +- org.hl7.fhir.report/pom.xml | 2 +- org.hl7.fhir.utilities/pom.xml | 2 +- org.hl7.fhir.validation.cli/pom.xml | 2 +- org.hl7.fhir.validation/pom.xml | 2 +- pom.xml | 2 +- 12 files changed, 11 insertions(+), 16 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index c8185536a..e69de29bb 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,5 +0,0 @@ -Validator: -* No changes - -Other code changes: -* Support lenient mode on FIHRPath when referring to polymorphics diff --git a/org.hl7.fhir.convertors/pom.xml b/org.hl7.fhir.convertors/pom.xml index 3421ff53d..1f9619f6e 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 - 5.1.11 + 5.1.12-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.dstu2/pom.xml b/org.hl7.fhir.dstu2/pom.xml index 67e6a8300..c284e5ebe 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 - 5.1.11 + 5.1.12-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.dstu2016may/pom.xml b/org.hl7.fhir.dstu2016may/pom.xml index bf8010cbf..19328d407 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 - 5.1.11 + 5.1.12-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.dstu3/pom.xml b/org.hl7.fhir.dstu3/pom.xml index 9128c2fdb..4cd27a42a 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 - 5.1.11 + 5.1.12-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.r4/pom.xml b/org.hl7.fhir.r4/pom.xml index 0549d92f7..5d3c135bd 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 - 5.1.11 + 5.1.12-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.r5/pom.xml b/org.hl7.fhir.r5/pom.xml index 7ee278061..0479bc832 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 - 5.1.11 + 5.1.12-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.report/pom.xml b/org.hl7.fhir.report/pom.xml index 9e8858101..74d68a5d1 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 - 5.1.11 + 5.1.12-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.utilities/pom.xml b/org.hl7.fhir.utilities/pom.xml index 692b0d690..b51be4514 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 - 5.1.11 + 5.1.12-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.validation.cli/pom.xml b/org.hl7.fhir.validation.cli/pom.xml index af3a67c91..fb3b3fcf4 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 - 5.1.11 + 5.1.12-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.validation/pom.xml b/org.hl7.fhir.validation/pom.xml index 1d22cb5f3..54f1835bc 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 - 5.1.11 + 5.1.12-SNAPSHOT ../pom.xml diff --git a/pom.xml b/pom.xml index 5e00c4e16..87f56d509 100644 --- a/pom.xml +++ b/pom.xml @@ -13,7 +13,7 @@ each other. It is fine to bump the point version of this POM without affecting HAPI FHIR. --> - 5.1.11 + 5.1.12-SNAPSHOT 5.1.0 From 25cac32326f7a0828b1af89175a68ba353973fd0 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Thu, 17 Sep 2020 15:39:14 +1000 Subject: [PATCH 05/73] depend on 1.1.42-snapshot --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 87f56d509..6f9443f5c 100644 --- a/pom.xml +++ b/pom.xml @@ -17,7 +17,7 @@ 5.1.0 - 1.1.41 + 1.1.42-SNAPSHOT 5.6.2 3.0.0-M4 0.8.5 From 54d320bb7b69cff367861c848eae99d065aa16fc Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Thu, 17 Sep 2020 15:40:06 +1000 Subject: [PATCH 06/73] Don't make a column for definitions in a code system if there are none --- .../fhir/r5/renderers/CodeSystemRenderer.java | 83 ++++++++++++------- 1 file changed, 52 insertions(+), 31 deletions(-) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/CodeSystemRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/CodeSystemRenderer.java index c6abb1b4a..028b2c68a 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/CodeSystemRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/CodeSystemRenderer.java @@ -134,6 +134,7 @@ public class CodeSystemRenderer extends TerminologyRenderer { return false; } XhtmlNode t = x.table( "codes"); + boolean definitions = false; boolean commentS = false; boolean deprecated = false; boolean display = false; @@ -161,14 +162,15 @@ public class CodeSystemRenderer extends TerminologyRenderer { display = display || conceptsHaveDisplay(c); version = version || conceptsHaveVersion(c); hierarchy = hierarchy || c.hasConcept(); + definitions = definitions || conceptsHaveDefinition(c); } CodeSystemNavigator csNav = new CodeSystemNavigator(cs); hierarchy = hierarchy || csNav.isRestructure(); List langs = new ArrayList<>(); - addMapHeaders(addTableHeaderRowStandard(t, hierarchy, display, true, commentS, version, deprecated, properties, null, false), maps); + addMapHeaders(addTableHeaderRowStandard(t, hierarchy, display, definitions, commentS, version, deprecated, properties, null, false), maps); for (ConceptDefinitionComponent c : csNav.getConcepts(null)) { - hasExtensions = addDefineRowToTable(t, c, 0, hierarchy, display, commentS, version, deprecated, maps, cs.getUrl(), cs, properties, csNav, langs) || hasExtensions; + hasExtensions = addDefineRowToTable(t, c, 0, hierarchy, display, definitions, commentS, version, deprecated, maps, cs.getUrl(), cs, properties, csNav, langs) || hasExtensions; } if (langs.size() > 0) { Collections.sort(langs); @@ -185,6 +187,23 @@ public class CodeSystemRenderer extends TerminologyRenderer { return hasExtensions; } + private boolean conceptsHaveDefinition(ConceptDefinitionComponent c) { + if (c.hasDefinition()) { + return true; + } + for (ConceptDefinitionDesignationComponent cd : c.getDesignation()) { + if (cd.getUse().is("http://terminology.hl7.org/CodeSystem/designation-usage", "definition") && cd.hasLanguage() && !c.getDefinition().equalsIgnoreCase(cd.getValue())) { + return true; + } + } + for (ConceptDefinitionComponent g : c.getConcept()) { + if (conceptsHaveDefinition(g)) { + return true; + } + } + return false; + } + private boolean conceptsHaveProperty(ConceptDefinitionComponent c, PropertyComponent cp) { if (CodeSystemUtilities.hasProperty(c, cp.getCode())) return true; @@ -271,7 +290,7 @@ public class CodeSystemRenderer extends TerminologyRenderer { - private boolean addDefineRowToTable(XhtmlNode t, ConceptDefinitionComponent c, int level, boolean hasHierarchy, boolean hasDisplay, boolean comment, boolean version, boolean deprecated, List maps, String system, CodeSystem cs, List properties, CodeSystemNavigator csNav, List langs) throws FHIRFormatError, DefinitionException, IOException { + private boolean addDefineRowToTable(XhtmlNode t, ConceptDefinitionComponent c, int level, boolean hasHierarchy, boolean hasDisplay, boolean hasDefinitions, boolean comment, boolean version, boolean deprecated, List maps, String system, CodeSystem cs, List properties, CodeSystemNavigator csNav, List langs) throws FHIRFormatError, DefinitionException, IOException { boolean hasExtensions = false; XhtmlNode tr = t.tr(); XhtmlNode td = tr.td(); @@ -297,36 +316,38 @@ public class CodeSystemRenderer extends TerminologyRenderer { if (hasDisplay) { td = tr.td(); renderDisplayName(c, cs, td); - } - td = tr.td(); - if (c != null && - c.hasDefinitionElement()) { - if (getContext().getLang() == null) { - if (hasMarkdownInDefinitions(cs)) - addMarkdown(td, c.getDefinition()); - else + } + if (hasDefinitions) { + td = tr.td(); + if (c != null && + c.hasDefinitionElement()) { + if (getContext().getLang() == null) { + if (hasMarkdownInDefinitions(cs)) + addMarkdown(td, c.getDefinition()); + else + td.addText(c.getDefinition()); + } else if (getContext().getLang().equals("*")) { + boolean sl = false; + for (ConceptDefinitionDesignationComponent cd : c.getDesignation()) + if (cd.getUse().is("http://terminology.hl7.org/CodeSystem/designation-usage", "definition") && cd.hasLanguage() && !c.getDefinition().equalsIgnoreCase(cd.getValue())) + sl = true; + td.addText((sl ? cs.getLanguage("en")+": " : "")+c.getDefinition()); + for (ConceptDefinitionDesignationComponent cd : c.getDesignation()) { + if (cd.getUse().is("http://terminology.hl7.org/CodeSystem/designation-usage", "definition") && cd.hasLanguage() && !c.getDefinition().equalsIgnoreCase(cd.getValue())) { + td.br(); + td.addText(cd.getLanguage()+": "+cd.getValue()); + } + } + } else if (getContext().getLang().equals(cs.getLanguage()) || (getContext().getLang().equals("en") && !cs.hasLanguage())) { td.addText(c.getDefinition()); - } else if (getContext().getLang().equals("*")) { - boolean sl = false; - for (ConceptDefinitionDesignationComponent cd : c.getDesignation()) - if (cd.getUse().is("http://terminology.hl7.org/CodeSystem/designation-usage", "definition") && cd.hasLanguage() && !c.getDefinition().equalsIgnoreCase(cd.getValue())) - sl = true; - td.addText((sl ? cs.getLanguage("en")+": " : "")+c.getDefinition()); - for (ConceptDefinitionDesignationComponent cd : c.getDesignation()) { - if (cd.getUse().is("http://terminology.hl7.org/CodeSystem/designation-usage", "definition") && cd.hasLanguage() && !c.getDefinition().equalsIgnoreCase(cd.getValue())) { - td.br(); - td.addText(cd.getLanguage()+": "+cd.getValue()); + } else { + for (ConceptDefinitionDesignationComponent cd : c.getDesignation()) { + if (cd.getUse().is("http://terminology.hl7.org/CodeSystem/designation-usage", "definition") && cd.hasLanguage() && cd.getLanguage().equals(getContext().getLang())) { + td.addText(cd.getValue()); + } } } - } else if (getContext().getLang().equals(cs.getLanguage()) || (getContext().getLang().equals("en") && !cs.hasLanguage())) { - td.addText(c.getDefinition()); - } else { - for (ConceptDefinitionDesignationComponent cd : c.getDesignation()) { - if (cd.getUse().is("http://terminology.hl7.org/CodeSystem/designation-usage", "definition") && cd.hasLanguage() && cd.getLanguage().equals(getContext().getLang())) { - td.addText(cd.getValue()); - } - } - } + } } if (deprecated) { td = tr.td(); @@ -427,7 +448,7 @@ public class CodeSystemRenderer extends TerminologyRenderer { } List ocl = csNav.getOtherChildren(c); for (ConceptDefinitionComponent cc : csNav.getConcepts(c)) { - hasExtensions = addDefineRowToTable(t, cc, level+1, hasHierarchy, hasDisplay, comment, version, deprecated, maps, system, cs, properties, csNav, langs) || hasExtensions; + hasExtensions = addDefineRowToTable(t, cc, level+1, hasHierarchy, hasDisplay, hasDefinitions, comment, version, deprecated, maps, system, cs, properties, csNav, langs) || hasExtensions; } for (ConceptDefinitionComponent cc : ocl) { tr = t.tr(); From 8ce405cc4dc1c69ab9be225cdfdbf4ae5cfb09bc Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Thu, 17 Sep 2020 15:40:46 +1000 Subject: [PATCH 07/73] special case support for fr-CA language --- .../main/java/org/hl7/fhir/r5/renderers/DataRenderer.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DataRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DataRenderer.java index b13bc6fd1..a3531ce7c 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DataRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DataRenderer.java @@ -168,6 +168,10 @@ public class DataRenderer extends Renderer { } protected String describeLang(String lang) { + // special cases: + if ("fr-CA".equals(lang)) { + return "French (Canadian)"; // this one was omitted from the value set + } ValueSet v = getContext().getWorker().fetchResource(ValueSet.class, "http://hl7.org/fhir/ValueSet/languages"); if (v != null) { ConceptReferenceComponent l = null; @@ -176,8 +180,9 @@ public class DataRenderer extends Renderer { l = cc; } if (l == null) { - if (lang.contains("-")) + if (lang.contains("-")) { lang = lang.substring(0, lang.indexOf("-")); + } for (ConceptReferenceComponent cc : v.getCompose().getIncludeFirstRep().getConcept()) { if (cc.getCode().equals(lang) || cc.getCode().startsWith(lang+"-")) l = cc; From 3464643921c5db33687b8bb2f14d450b1503e62d Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Thu, 17 Sep 2020 15:41:32 +1000 Subject: [PATCH 08/73] Prevent NPE when auto-generating narrative and an illegal resource type is encountered --- .../fhir/r5/renderers/ProfileDrivenRenderer.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ProfileDrivenRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ProfileDrivenRenderer.java index 9f3ebdbdd..4ab610b78 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ProfileDrivenRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ProfileDrivenRenderer.java @@ -106,13 +106,14 @@ public class ProfileDrivenRenderer extends ResourceRenderer { } try { StructureDefinition sd = r.getDefinition(); - ElementDefinition ed = sd.getSnapshot().getElement().get(0); - if (sd.getType().equals("NamingSystem") && "icd10".equals(r.getId())) { - System.out.println("hah!"); + if (sd == null) { + throw new FHIRException("Cannot find definition for "+r.fhirType()); + } else { + ElementDefinition ed = sd.getSnapshot().getElement().get(0); + containedIds.clear(); + hasExtensions = false; + generateByProfile(r, sd, r.root(), sd.getSnapshot().getElement(), ed, context.getProfileUtilities().getChildList(sd, ed), x, r.fhirType(), false, 0); } - containedIds.clear(); - hasExtensions = false; - generateByProfile(r, sd, r.root(), sd.getSnapshot().getElement(), ed, context.getProfileUtilities().getChildList(sd, ed), x, r.fhirType(), false, 0); } catch (Exception e) { e.printStackTrace(); x.para().b().style("color: maroon").tx("Exception generating Narrative: "+e.getMessage()); From 2e7e277c97e6a1833dd3ea928052fb75803480fd Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Thu, 17 Sep 2020 15:42:03 +1000 Subject: [PATCH 09/73] Prevent NPE resolving resource in batch --- .../src/main/java/org/hl7/fhir/r5/renderers/utils/Resolver.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/Resolver.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/Resolver.java index 94c413b31..84f0a748d 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/Resolver.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/Resolver.java @@ -126,7 +126,7 @@ public class Resolver { if (containerElement != null) { for (org.hl7.fhir.r5.elementmodel.Element p : containerElement.getChildren("parameter")) { org.hl7.fhir.r5.elementmodel.Element res = p.getNamedChild("resource"); - if (value.equals(res.fhirType()+"/"+res.getChildValue("id"))) + if (res != null && value.equals(res.fhirType()+"/"+res.getChildValue("id"))) return p; } } From 9d223379299020c071b4ba10ebce9794158c622c Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Thu, 17 Sep 2020 15:42:45 +1000 Subject: [PATCH 10/73] fix value set validation for primitive types when an expansion is provided, and the code system is not known --- .../org/hl7/fhir/r5/terminologies/ValueSetCheckerSimple.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/ValueSetCheckerSimple.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/ValueSetCheckerSimple.java index e8f89e701..cbb70ea89 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/ValueSetCheckerSimple.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/ValueSetCheckerSimple.java @@ -164,6 +164,9 @@ public class ValueSetCheckerSimple implements ValueSetChecker { throw new FHIRException("Unable to evaluate based on empty code system"); } res = validateCode(code, cs); + } else if (cs == null && valueset.hasExpansion() && inExpansion) { + // we just take the value set as face value then + res = new ValidationResult(IssueSeverity.INFORMATION, null); } else { // well, we didn't find a code system - try the expansion? // disabled waiting for discussion From e33ffca7495c3b6d0245f6f0e65f234aa9c867d0 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Thu, 17 Sep 2020 15:44:45 +1000 Subject: [PATCH 11/73] FHIRPath engine: correction for allowing boolean conversion of primitive types --- .../org/hl7/fhir/r5/utils/FHIRPathEngine.java | 41 +++++++++++++++---- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java index 609e4ffec..4a71849c6 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java @@ -3853,7 +3853,7 @@ public class FHIRPathEngine { } else {// (exp.getParameters().size() == 0) { boolean all = true; for (Base item : focus) { - Equality eq = asBool(item); + Equality eq = asBool(item, true); if (eq != Equality.True) { all = false; break; @@ -4471,7 +4471,11 @@ public class FHIRPathEngine { } else { boolean all = true; for (Base item : focus) { - Equality v = asBool(item); + if (!canConvertToBoolean(item)) { + throw new FHIRException("Unable to convert '"+convertToString(item)+"' to a boolean"); + } + + Equality v = asBool(item, true); if (v != Equality.False) { all = false; break; @@ -4501,7 +4505,11 @@ public class FHIRPathEngine { } else { boolean any = false; for (Base item : focus) { - Equality v = asBool(item); + if (!canConvertToBoolean(item)) { + throw new FHIRException("Unable to convert '"+convertToString(item)+"' to a boolean"); + } + + Equality v = asBool(item, true); if (v == Equality.False) { any = true; break; @@ -4531,8 +4539,11 @@ public class FHIRPathEngine { } else { boolean all = true; for (Base item : focus) { - Equality v = asBool(item); - if (v != Equality.True) { + if (!canConvertToBoolean(item)) { + throw new FHIRException("Unable to convert '"+convertToString(item)+"' to a boolean"); + } + Equality v = asBool(item, true); + if (v != Equality.True) { all = false; break; } @@ -4561,7 +4572,11 @@ public class FHIRPathEngine { } else { boolean any = false; for (Base item : focus) { - Equality v = asBool(item); + if (!canConvertToBoolean(item)) { + throw new FHIRException("Unable to convert '"+convertToString(item)+"' to a boolean"); + } + + Equality v = asBool(item, true); if (v == Equality.True) { any = true; break; @@ -4572,7 +4587,11 @@ public class FHIRPathEngine { return result; } - private List funcTrace(ExecutionContext context, List focus, ExpressionNode exp) throws FHIRException { + private boolean canConvertToBoolean(Base item) { + return (item.isBooleanPrimitive); + } + + private List funcTrace(ExecutionContext context, List focus, ExpressionNode exp) throws FHIRException { List nl = execute(context, focus, exp.getParameters().get(0), true); String name = nl.get(0).primitiveValue(); if (exp.getParameters().size() == 2) { @@ -5493,8 +5512,10 @@ public class FHIRPathEngine { private Equality asBool(List items) throws PathEngineException { if (items.size() == 0) { return Equality.Null; + } else if (items.size() == 1 && items.get(0).isBooleanPrimitive()) { + return asBool(items.get(0), true); } else if (items.size() == 1) { - return asBool(items.get(0)); + return Equality.True; } else { throw makeException(I18nConstants.FHIRPATH_UNABLE_BOOLEAN, convertToString(items)); } @@ -5528,7 +5549,7 @@ public class FHIRPathEngine { } } - private Equality asBool(Base item) { + private Equality asBool(Base item, boolean narrow) { if (item instanceof BooleanType) { return boolToTriState(((BooleanType) item).booleanValue()); } else if (item.isBooleanPrimitive()) { @@ -5539,6 +5560,8 @@ public class FHIRPathEngine { } else { return Equality.Null; } + } else if (narrow) { + return Equality.False; } else if (item instanceof IntegerType || Utilities.existsInList(item.fhirType(), "integer", "positiveint", "unsignedInt")) { return asBoolFromInt(item.primitiveValue()); } else if (item instanceof DecimalType || Utilities.existsInList(item.fhirType(), "decimal")) { From fa778fbf03ccfe155b6d7b5a7f6e647eca418fc3 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Thu, 17 Sep 2020 15:45:47 +1000 Subject: [PATCH 12/73] Fix handling resources in bundles when type is profiled --- .../src/main/resources/Messages.properties | 10 +++++----- .../fhir/validation/instance/InstanceValidator.java | 11 ++++++++--- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/org.hl7.fhir.utilities/src/main/resources/Messages.properties b/org.hl7.fhir.utilities/src/main/resources/Messages.properties index 8a13d0256..562e34887 100644 --- a/org.hl7.fhir.utilities/src/main/resources/Messages.properties +++ b/org.hl7.fhir.utilities/src/main/resources/Messages.properties @@ -10,8 +10,8 @@ Bundle_BUNDLE_Entry_NoFullUrl = Bundle entry missing fullUrl Bundle_BUNDLE_Entry_NoProfile = No profile found for contained resource of type ''{0}'' Bundle_BUNDLE_Entry_NotFound = Can''t find ''{0}'' in the bundle ({1}) Bundle_BUNDLE_Entry_Orphan = Entry {0} isn''t reachable by traversing from first Bundle entry -Bundle_BUNDLE_Entry_Type = The type ''{0}'' is not valid - no resources allowed here -Bundle_BUNDLE_Entry_Type2 = The type ''{0}'' is not valid - must be {1} +Bundle_BUNDLE_Entry_Type = The type ''{0}'' is not valid - no resources allowed here (allowed = {1}) +Bundle_BUNDLE_Entry_Type2 = The type ''{0}'' is not valid - must be {1} (allowed = {2}) Bundle_BUNDLE_Entry_Type3 = The type ''{0}'' is not valid - must be one of {1} Bundle_BUNDLE_FullUrl_Missing = Relative Reference appears inside Bundle whose entry is missing a fullUrl Bundle_BUNDLE_FullUrl_NeedVersion = Entries matching fullURL {0} should declare meta/versionId because there are version-specific references @@ -156,9 +156,9 @@ Terminology_TX_NoValid_17 = The value provided (''{0}'') is not in the value set Terminology_TX_NoValid_18 = The value provided (''{0}'') is not in the value set {1} ({2}), and a code is recommended to come from this value set){3} Terminology_TX_NoValid_2 = None of the codes provided are in the value set {0} ({1}), and a code should come from this value set unless it has no suitable code) (codes = {2}) Terminology_TX_NoValid_3 = None of the codes provided are in the value set {0} ({1}), and a code is recommended to come from this value set) (codes = {2}) -Terminology_TX_NoValid_4 = The Coding provided ({2}) is not in the value set {0}, and a code is required from this value set{1} -Terminology_TX_NoValid_5 = The Coding provided ({2}) is not in the value set {0}, and a code should come from this value set unless it has no suitable code{1} -Terminology_TX_NoValid_6 = The Coding provided ({2}) is not in the value set {0}, and a code is recommended to come from this value set{1} +Terminology_TX_NoValid_4 = The Coding provided ({2}) is not in the value set {0}, and a code is required from this value set {1} +Terminology_TX_NoValid_5 = The Coding provided ({2}) is not in the value set {0}, and a code should come from this value set unless it has no suitable code {1} +Terminology_TX_NoValid_6 = The Coding provided ({2}) is not in the value set {0}, and a code is recommended to come from this value set {1} Terminology_TX_NoValid_7 = None of the codes provided could be validated against the maximum value set {0} ({1}), (error = {2}) Terminology_TX_NoValid_8 = None of the codes provided are in the maximum value set {0} ({1}), and a code from this value set is required) (codes = {2}) Terminology_TX_NoValid_9 = The code provided could not be validated against the maximum value set {0} ({1}), (error = {2}) 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 5f641c3c9..02aee0df3 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 @@ -3943,15 +3943,17 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat private void validateContains(ValidatorHostContext hostContext, List errors, String path, ElementDefinition child, ElementDefinition context, Element resource, Element element, NodeStack stack, IdStatus idstatus) throws FHIRException { String resourceName = element.getType(); TypeRefComponent trr = null; + CommaSeparatedStringBuilder bt = new CommaSeparatedStringBuilder(); for (TypeRefComponent tr : child.getType()) { - if (tr.getCode().equals("Resource")) { + bt.append(tr.getCode()); + if (tr.getCode().equals("Resource") || tr.getCode().equals(resourceName) ) { trr = tr; break; } } stack.qualifyPath(".ofType("+resourceName+")"); if (trr == null) { - rule(errors, IssueType.INFORMATIONAL, element.line(), element.col(), stack.getLiteralPath(), false, I18nConstants.BUNDLE_BUNDLE_ENTRY_TYPE, resourceName); + rule(errors, IssueType.INFORMATIONAL, element.line(), element.col(), stack.getLiteralPath(), false, I18nConstants.BUNDLE_BUNDLE_ENTRY_TYPE, resourceName, bt.toString()); } else if (isValidResourceType(resourceName, trr)) { // special case: resource wrapper is reset if we're crossing a bundle boundary, but not otherwise ValidatorHostContext hc = null; @@ -4002,7 +4004,10 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } private boolean isValidResourceType(String type, TypeRefComponent def) { - if (!def.hasProfile()) { + if (!def.hasProfile() && def.getCode().equals("Resource")) { + return true; + } + if (def.getCode().equals(type)) { return true; } List list = new ArrayList<>(); From 0dcf64cb7028661f52aee6c203dc0382f3d1549f Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Thu, 17 Sep 2020 17:04:42 +1000 Subject: [PATCH 13/73] Add test cases for wildcard versions --- .../org/hl7/fhir/r5/utils/FHIRPathEngine.java | 2 +- .../hl7/fhir/utilities/VersionUtilities.java | 2 +- .../cache/FilesystemPackageCacheManager.java | 19 +++++++++++-------- .../utilities/tests/PackageCacheTests.java | 10 ++++++++++ 4 files changed, 23 insertions(+), 10 deletions(-) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java index 4a71849c6..5b6c553ff 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java @@ -4588,7 +4588,7 @@ public class FHIRPathEngine { } private boolean canConvertToBoolean(Base item) { - return (item.isBooleanPrimitive); + return (item.isBooleanPrimitive()); } private List funcTrace(ExecutionContext context, List focus, ExpressionNode exp) throws FHIRException { diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/VersionUtilities.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/VersionUtilities.java index 91e8d46b2..c90530f2a 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/VersionUtilities.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/VersionUtilities.java @@ -240,7 +240,7 @@ public class VersionUtilities { public static boolean isMajMinOrLaterPatch(String test, String current) { String t = getMajMin(test); String c = getMajMin(current); - if (c.compareTo(t) == 0) { + if (c != null && c.compareTo(t) == 0) { String pt = getPatch(test); String pc = getPatch(current); if (pt==null || "x".equals(pt)) { diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/FilesystemPackageCacheManager.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/FilesystemPackageCacheManager.java index 4415901af..4d6b9f11d 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/FilesystemPackageCacheManager.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/FilesystemPackageCacheManager.java @@ -311,14 +311,17 @@ public class FilesystemPackageCacheManager extends BasePackageCacheManager imple String foundPackage = null; String foundVersion = null; for (String f : sorted(new File(cacheFolder).list())) { - if (f.equals(id + "#" + version) || (Utilities.noString(version) && f.startsWith(id + "#"))) { - return loadPackageInfo(Utilities.path(cacheFolder, f)); - } - if (version!=null && version.endsWith(".x") && f.contains("#")) { - String[] parts = f.split("#"); - if (parts[0].equals(id) && VersionUtilities.isMajMinOrLaterPatch((foundVersion!=null ? foundVersion : version),parts[1])) { - foundVersion = parts[1]; - foundPackage = f; + File cf = new File(Utilities.path(cacheFolder, f)); + if (cf.isDirectory()) { + if (f.equals(id + "#" + version) || (Utilities.noString(version) && f.startsWith(id + "#"))) { + return loadPackageInfo(Utilities.path(cacheFolder, f)); + } + if (version != null && version.endsWith(".x") && f.contains("#")) { + String[] parts = f.split("#"); + if (parts[0].equals(id) && VersionUtilities.isMajMinOrLaterPatch((foundVersion!=null ? foundVersion : version),parts[1])) { + foundVersion = parts[1]; + foundPackage = f; + } } } } diff --git a/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/tests/PackageCacheTests.java b/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/tests/PackageCacheTests.java index 4f42035eb..8e8289fbd 100644 --- a/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/tests/PackageCacheTests.java +++ b/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/tests/PackageCacheTests.java @@ -37,4 +37,14 @@ public class PackageCacheTests { list = cache.listPackages(); Assertions.assertFalse(list.isEmpty()); } + + @Test + public void testPatchWildCard() throws IOException { + FilesystemPackageCacheManager cache = new FilesystemPackageCacheManager(true, ToolsVersion.TOOLS_VERSION); + cache.clear(); + Assertions.assertEquals(cache.loadPackage("hl7.fhir.us.core", "3.1.0").version(), "3.1.0"); + Assertions.assertEquals(cache.loadPackage("hl7.fhir.us.core", "3.1.1").version(), "3.1.1"); + Assertions.assertEquals(cache.loadPackage("hl7.fhir.us.core", "3.1.x").version(), "3.1.1"); + Assertions.assertEquals(cache.loadPackage("hl7.fhir.us.core", "3.0.x").version(), "3.0.1"); + } } \ No newline at end of file From a47e8060160b6109eba01ab50404be95f029652d Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Thu, 17 Sep 2020 17:04:59 +1000 Subject: [PATCH 14/73] release notes --- RELEASE_NOTES.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index e69de29bb..5c49d3361 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -0,0 +1,11 @@ +Validator: +* Fix handling resources in bundles when type is profiled +* Prevent NPE resolving resource in batch +* fix value set validation for primitive types when an expansion is provided, and the code system is not known + +Other Changes: +* Package Subsystem - Support wildcars for patch version +* Renderer: Don't make a column for definitions in a code system if there are none +* Renderer: special case support for fr-CA language +* Renderer: Prevent NPE when auto-generating narrative and an illegal resource type is encountered +* FHIRPath Engine: correction for allowing boolean conversion of primitive types From 75921b723bd92f2a34a0d9302a90c0f24545c7d7 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Thu, 17 Sep 2020 23:52:05 +1000 Subject: [PATCH 15/73] Various fixes (#348) * depend on 1.1.42-snapshot * Don't make a column for definitions in a code system if there are none * special case support for fr-CA language * Prevent NPE when auto-generating narrative and an illegal resource type is encountered * Prevent NPE resolving resource in batch * fix value set validation for primitive types when an expansion is provided, and the code system is not known * FHIRPath engine: correction for allowing boolean conversion of primitive types * Fix handling resources in bundles when type is profiled * Add test cases for wildcard versions * release notes --- RELEASE_NOTES.md | 11 +++ .../fhir/r5/renderers/CodeSystemRenderer.java | 83 ++++++++++++------- .../hl7/fhir/r5/renderers/DataRenderer.java | 7 +- .../r5/renderers/ProfileDrivenRenderer.java | 13 +-- .../hl7/fhir/r5/renderers/utils/Resolver.java | 2 +- .../terminologies/ValueSetCheckerSimple.java | 3 + .../org/hl7/fhir/r5/utils/FHIRPathEngine.java | 41 +++++++-- .../hl7/fhir/utilities/VersionUtilities.java | 2 +- .../cache/FilesystemPackageCacheManager.java | 19 +++-- .../src/main/resources/Messages.properties | 10 +-- .../utilities/tests/PackageCacheTests.java | 10 +++ .../instance/InstanceValidator.java | 11 ++- pom.xml | 2 +- 13 files changed, 148 insertions(+), 66 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index e69de29bb..5c49d3361 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -0,0 +1,11 @@ +Validator: +* Fix handling resources in bundles when type is profiled +* Prevent NPE resolving resource in batch +* fix value set validation for primitive types when an expansion is provided, and the code system is not known + +Other Changes: +* Package Subsystem - Support wildcars for patch version +* Renderer: Don't make a column for definitions in a code system if there are none +* Renderer: special case support for fr-CA language +* Renderer: Prevent NPE when auto-generating narrative and an illegal resource type is encountered +* FHIRPath Engine: correction for allowing boolean conversion of primitive types diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/CodeSystemRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/CodeSystemRenderer.java index c6abb1b4a..028b2c68a 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/CodeSystemRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/CodeSystemRenderer.java @@ -134,6 +134,7 @@ public class CodeSystemRenderer extends TerminologyRenderer { return false; } XhtmlNode t = x.table( "codes"); + boolean definitions = false; boolean commentS = false; boolean deprecated = false; boolean display = false; @@ -161,14 +162,15 @@ public class CodeSystemRenderer extends TerminologyRenderer { display = display || conceptsHaveDisplay(c); version = version || conceptsHaveVersion(c); hierarchy = hierarchy || c.hasConcept(); + definitions = definitions || conceptsHaveDefinition(c); } CodeSystemNavigator csNav = new CodeSystemNavigator(cs); hierarchy = hierarchy || csNav.isRestructure(); List langs = new ArrayList<>(); - addMapHeaders(addTableHeaderRowStandard(t, hierarchy, display, true, commentS, version, deprecated, properties, null, false), maps); + addMapHeaders(addTableHeaderRowStandard(t, hierarchy, display, definitions, commentS, version, deprecated, properties, null, false), maps); for (ConceptDefinitionComponent c : csNav.getConcepts(null)) { - hasExtensions = addDefineRowToTable(t, c, 0, hierarchy, display, commentS, version, deprecated, maps, cs.getUrl(), cs, properties, csNav, langs) || hasExtensions; + hasExtensions = addDefineRowToTable(t, c, 0, hierarchy, display, definitions, commentS, version, deprecated, maps, cs.getUrl(), cs, properties, csNav, langs) || hasExtensions; } if (langs.size() > 0) { Collections.sort(langs); @@ -185,6 +187,23 @@ public class CodeSystemRenderer extends TerminologyRenderer { return hasExtensions; } + private boolean conceptsHaveDefinition(ConceptDefinitionComponent c) { + if (c.hasDefinition()) { + return true; + } + for (ConceptDefinitionDesignationComponent cd : c.getDesignation()) { + if (cd.getUse().is("http://terminology.hl7.org/CodeSystem/designation-usage", "definition") && cd.hasLanguage() && !c.getDefinition().equalsIgnoreCase(cd.getValue())) { + return true; + } + } + for (ConceptDefinitionComponent g : c.getConcept()) { + if (conceptsHaveDefinition(g)) { + return true; + } + } + return false; + } + private boolean conceptsHaveProperty(ConceptDefinitionComponent c, PropertyComponent cp) { if (CodeSystemUtilities.hasProperty(c, cp.getCode())) return true; @@ -271,7 +290,7 @@ public class CodeSystemRenderer extends TerminologyRenderer { - private boolean addDefineRowToTable(XhtmlNode t, ConceptDefinitionComponent c, int level, boolean hasHierarchy, boolean hasDisplay, boolean comment, boolean version, boolean deprecated, List maps, String system, CodeSystem cs, List properties, CodeSystemNavigator csNav, List langs) throws FHIRFormatError, DefinitionException, IOException { + private boolean addDefineRowToTable(XhtmlNode t, ConceptDefinitionComponent c, int level, boolean hasHierarchy, boolean hasDisplay, boolean hasDefinitions, boolean comment, boolean version, boolean deprecated, List maps, String system, CodeSystem cs, List properties, CodeSystemNavigator csNav, List langs) throws FHIRFormatError, DefinitionException, IOException { boolean hasExtensions = false; XhtmlNode tr = t.tr(); XhtmlNode td = tr.td(); @@ -297,36 +316,38 @@ public class CodeSystemRenderer extends TerminologyRenderer { if (hasDisplay) { td = tr.td(); renderDisplayName(c, cs, td); - } - td = tr.td(); - if (c != null && - c.hasDefinitionElement()) { - if (getContext().getLang() == null) { - if (hasMarkdownInDefinitions(cs)) - addMarkdown(td, c.getDefinition()); - else + } + if (hasDefinitions) { + td = tr.td(); + if (c != null && + c.hasDefinitionElement()) { + if (getContext().getLang() == null) { + if (hasMarkdownInDefinitions(cs)) + addMarkdown(td, c.getDefinition()); + else + td.addText(c.getDefinition()); + } else if (getContext().getLang().equals("*")) { + boolean sl = false; + for (ConceptDefinitionDesignationComponent cd : c.getDesignation()) + if (cd.getUse().is("http://terminology.hl7.org/CodeSystem/designation-usage", "definition") && cd.hasLanguage() && !c.getDefinition().equalsIgnoreCase(cd.getValue())) + sl = true; + td.addText((sl ? cs.getLanguage("en")+": " : "")+c.getDefinition()); + for (ConceptDefinitionDesignationComponent cd : c.getDesignation()) { + if (cd.getUse().is("http://terminology.hl7.org/CodeSystem/designation-usage", "definition") && cd.hasLanguage() && !c.getDefinition().equalsIgnoreCase(cd.getValue())) { + td.br(); + td.addText(cd.getLanguage()+": "+cd.getValue()); + } + } + } else if (getContext().getLang().equals(cs.getLanguage()) || (getContext().getLang().equals("en") && !cs.hasLanguage())) { td.addText(c.getDefinition()); - } else if (getContext().getLang().equals("*")) { - boolean sl = false; - for (ConceptDefinitionDesignationComponent cd : c.getDesignation()) - if (cd.getUse().is("http://terminology.hl7.org/CodeSystem/designation-usage", "definition") && cd.hasLanguage() && !c.getDefinition().equalsIgnoreCase(cd.getValue())) - sl = true; - td.addText((sl ? cs.getLanguage("en")+": " : "")+c.getDefinition()); - for (ConceptDefinitionDesignationComponent cd : c.getDesignation()) { - if (cd.getUse().is("http://terminology.hl7.org/CodeSystem/designation-usage", "definition") && cd.hasLanguage() && !c.getDefinition().equalsIgnoreCase(cd.getValue())) { - td.br(); - td.addText(cd.getLanguage()+": "+cd.getValue()); + } else { + for (ConceptDefinitionDesignationComponent cd : c.getDesignation()) { + if (cd.getUse().is("http://terminology.hl7.org/CodeSystem/designation-usage", "definition") && cd.hasLanguage() && cd.getLanguage().equals(getContext().getLang())) { + td.addText(cd.getValue()); + } } } - } else if (getContext().getLang().equals(cs.getLanguage()) || (getContext().getLang().equals("en") && !cs.hasLanguage())) { - td.addText(c.getDefinition()); - } else { - for (ConceptDefinitionDesignationComponent cd : c.getDesignation()) { - if (cd.getUse().is("http://terminology.hl7.org/CodeSystem/designation-usage", "definition") && cd.hasLanguage() && cd.getLanguage().equals(getContext().getLang())) { - td.addText(cd.getValue()); - } - } - } + } } if (deprecated) { td = tr.td(); @@ -427,7 +448,7 @@ public class CodeSystemRenderer extends TerminologyRenderer { } List ocl = csNav.getOtherChildren(c); for (ConceptDefinitionComponent cc : csNav.getConcepts(c)) { - hasExtensions = addDefineRowToTable(t, cc, level+1, hasHierarchy, hasDisplay, comment, version, deprecated, maps, system, cs, properties, csNav, langs) || hasExtensions; + hasExtensions = addDefineRowToTable(t, cc, level+1, hasHierarchy, hasDisplay, hasDefinitions, comment, version, deprecated, maps, system, cs, properties, csNav, langs) || hasExtensions; } for (ConceptDefinitionComponent cc : ocl) { tr = t.tr(); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DataRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DataRenderer.java index b13bc6fd1..a3531ce7c 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DataRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DataRenderer.java @@ -168,6 +168,10 @@ public class DataRenderer extends Renderer { } protected String describeLang(String lang) { + // special cases: + if ("fr-CA".equals(lang)) { + return "French (Canadian)"; // this one was omitted from the value set + } ValueSet v = getContext().getWorker().fetchResource(ValueSet.class, "http://hl7.org/fhir/ValueSet/languages"); if (v != null) { ConceptReferenceComponent l = null; @@ -176,8 +180,9 @@ public class DataRenderer extends Renderer { l = cc; } if (l == null) { - if (lang.contains("-")) + if (lang.contains("-")) { lang = lang.substring(0, lang.indexOf("-")); + } for (ConceptReferenceComponent cc : v.getCompose().getIncludeFirstRep().getConcept()) { if (cc.getCode().equals(lang) || cc.getCode().startsWith(lang+"-")) l = cc; diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ProfileDrivenRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ProfileDrivenRenderer.java index 9f3ebdbdd..4ab610b78 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ProfileDrivenRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ProfileDrivenRenderer.java @@ -106,13 +106,14 @@ public class ProfileDrivenRenderer extends ResourceRenderer { } try { StructureDefinition sd = r.getDefinition(); - ElementDefinition ed = sd.getSnapshot().getElement().get(0); - if (sd.getType().equals("NamingSystem") && "icd10".equals(r.getId())) { - System.out.println("hah!"); + if (sd == null) { + throw new FHIRException("Cannot find definition for "+r.fhirType()); + } else { + ElementDefinition ed = sd.getSnapshot().getElement().get(0); + containedIds.clear(); + hasExtensions = false; + generateByProfile(r, sd, r.root(), sd.getSnapshot().getElement(), ed, context.getProfileUtilities().getChildList(sd, ed), x, r.fhirType(), false, 0); } - containedIds.clear(); - hasExtensions = false; - generateByProfile(r, sd, r.root(), sd.getSnapshot().getElement(), ed, context.getProfileUtilities().getChildList(sd, ed), x, r.fhirType(), false, 0); } catch (Exception e) { e.printStackTrace(); x.para().b().style("color: maroon").tx("Exception generating Narrative: "+e.getMessage()); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/Resolver.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/Resolver.java index 94c413b31..84f0a748d 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/Resolver.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/Resolver.java @@ -126,7 +126,7 @@ public class Resolver { if (containerElement != null) { for (org.hl7.fhir.r5.elementmodel.Element p : containerElement.getChildren("parameter")) { org.hl7.fhir.r5.elementmodel.Element res = p.getNamedChild("resource"); - if (value.equals(res.fhirType()+"/"+res.getChildValue("id"))) + if (res != null && value.equals(res.fhirType()+"/"+res.getChildValue("id"))) return p; } } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/ValueSetCheckerSimple.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/ValueSetCheckerSimple.java index e8f89e701..cbb70ea89 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/ValueSetCheckerSimple.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/ValueSetCheckerSimple.java @@ -164,6 +164,9 @@ public class ValueSetCheckerSimple implements ValueSetChecker { throw new FHIRException("Unable to evaluate based on empty code system"); } res = validateCode(code, cs); + } else if (cs == null && valueset.hasExpansion() && inExpansion) { + // we just take the value set as face value then + res = new ValidationResult(IssueSeverity.INFORMATION, null); } else { // well, we didn't find a code system - try the expansion? // disabled waiting for discussion diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java index 609e4ffec..5b6c553ff 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java @@ -3853,7 +3853,7 @@ public class FHIRPathEngine { } else {// (exp.getParameters().size() == 0) { boolean all = true; for (Base item : focus) { - Equality eq = asBool(item); + Equality eq = asBool(item, true); if (eq != Equality.True) { all = false; break; @@ -4471,7 +4471,11 @@ public class FHIRPathEngine { } else { boolean all = true; for (Base item : focus) { - Equality v = asBool(item); + if (!canConvertToBoolean(item)) { + throw new FHIRException("Unable to convert '"+convertToString(item)+"' to a boolean"); + } + + Equality v = asBool(item, true); if (v != Equality.False) { all = false; break; @@ -4501,7 +4505,11 @@ public class FHIRPathEngine { } else { boolean any = false; for (Base item : focus) { - Equality v = asBool(item); + if (!canConvertToBoolean(item)) { + throw new FHIRException("Unable to convert '"+convertToString(item)+"' to a boolean"); + } + + Equality v = asBool(item, true); if (v == Equality.False) { any = true; break; @@ -4531,8 +4539,11 @@ public class FHIRPathEngine { } else { boolean all = true; for (Base item : focus) { - Equality v = asBool(item); - if (v != Equality.True) { + if (!canConvertToBoolean(item)) { + throw new FHIRException("Unable to convert '"+convertToString(item)+"' to a boolean"); + } + Equality v = asBool(item, true); + if (v != Equality.True) { all = false; break; } @@ -4561,7 +4572,11 @@ public class FHIRPathEngine { } else { boolean any = false; for (Base item : focus) { - Equality v = asBool(item); + if (!canConvertToBoolean(item)) { + throw new FHIRException("Unable to convert '"+convertToString(item)+"' to a boolean"); + } + + Equality v = asBool(item, true); if (v == Equality.True) { any = true; break; @@ -4572,7 +4587,11 @@ public class FHIRPathEngine { return result; } - private List funcTrace(ExecutionContext context, List focus, ExpressionNode exp) throws FHIRException { + private boolean canConvertToBoolean(Base item) { + return (item.isBooleanPrimitive()); + } + + private List funcTrace(ExecutionContext context, List focus, ExpressionNode exp) throws FHIRException { List nl = execute(context, focus, exp.getParameters().get(0), true); String name = nl.get(0).primitiveValue(); if (exp.getParameters().size() == 2) { @@ -5493,8 +5512,10 @@ public class FHIRPathEngine { private Equality asBool(List items) throws PathEngineException { if (items.size() == 0) { return Equality.Null; + } else if (items.size() == 1 && items.get(0).isBooleanPrimitive()) { + return asBool(items.get(0), true); } else if (items.size() == 1) { - return asBool(items.get(0)); + return Equality.True; } else { throw makeException(I18nConstants.FHIRPATH_UNABLE_BOOLEAN, convertToString(items)); } @@ -5528,7 +5549,7 @@ public class FHIRPathEngine { } } - private Equality asBool(Base item) { + private Equality asBool(Base item, boolean narrow) { if (item instanceof BooleanType) { return boolToTriState(((BooleanType) item).booleanValue()); } else if (item.isBooleanPrimitive()) { @@ -5539,6 +5560,8 @@ public class FHIRPathEngine { } else { return Equality.Null; } + } else if (narrow) { + return Equality.False; } else if (item instanceof IntegerType || Utilities.existsInList(item.fhirType(), "integer", "positiveint", "unsignedInt")) { return asBoolFromInt(item.primitiveValue()); } else if (item instanceof DecimalType || Utilities.existsInList(item.fhirType(), "decimal")) { diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/VersionUtilities.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/VersionUtilities.java index 91e8d46b2..c90530f2a 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/VersionUtilities.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/VersionUtilities.java @@ -240,7 +240,7 @@ public class VersionUtilities { public static boolean isMajMinOrLaterPatch(String test, String current) { String t = getMajMin(test); String c = getMajMin(current); - if (c.compareTo(t) == 0) { + if (c != null && c.compareTo(t) == 0) { String pt = getPatch(test); String pc = getPatch(current); if (pt==null || "x".equals(pt)) { diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/FilesystemPackageCacheManager.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/FilesystemPackageCacheManager.java index 4415901af..4d6b9f11d 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/FilesystemPackageCacheManager.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/FilesystemPackageCacheManager.java @@ -311,14 +311,17 @@ public class FilesystemPackageCacheManager extends BasePackageCacheManager imple String foundPackage = null; String foundVersion = null; for (String f : sorted(new File(cacheFolder).list())) { - if (f.equals(id + "#" + version) || (Utilities.noString(version) && f.startsWith(id + "#"))) { - return loadPackageInfo(Utilities.path(cacheFolder, f)); - } - if (version!=null && version.endsWith(".x") && f.contains("#")) { - String[] parts = f.split("#"); - if (parts[0].equals(id) && VersionUtilities.isMajMinOrLaterPatch((foundVersion!=null ? foundVersion : version),parts[1])) { - foundVersion = parts[1]; - foundPackage = f; + File cf = new File(Utilities.path(cacheFolder, f)); + if (cf.isDirectory()) { + if (f.equals(id + "#" + version) || (Utilities.noString(version) && f.startsWith(id + "#"))) { + return loadPackageInfo(Utilities.path(cacheFolder, f)); + } + if (version != null && version.endsWith(".x") && f.contains("#")) { + String[] parts = f.split("#"); + if (parts[0].equals(id) && VersionUtilities.isMajMinOrLaterPatch((foundVersion!=null ? foundVersion : version),parts[1])) { + foundVersion = parts[1]; + foundPackage = f; + } } } } diff --git a/org.hl7.fhir.utilities/src/main/resources/Messages.properties b/org.hl7.fhir.utilities/src/main/resources/Messages.properties index 8a13d0256..562e34887 100644 --- a/org.hl7.fhir.utilities/src/main/resources/Messages.properties +++ b/org.hl7.fhir.utilities/src/main/resources/Messages.properties @@ -10,8 +10,8 @@ Bundle_BUNDLE_Entry_NoFullUrl = Bundle entry missing fullUrl Bundle_BUNDLE_Entry_NoProfile = No profile found for contained resource of type ''{0}'' Bundle_BUNDLE_Entry_NotFound = Can''t find ''{0}'' in the bundle ({1}) Bundle_BUNDLE_Entry_Orphan = Entry {0} isn''t reachable by traversing from first Bundle entry -Bundle_BUNDLE_Entry_Type = The type ''{0}'' is not valid - no resources allowed here -Bundle_BUNDLE_Entry_Type2 = The type ''{0}'' is not valid - must be {1} +Bundle_BUNDLE_Entry_Type = The type ''{0}'' is not valid - no resources allowed here (allowed = {1}) +Bundle_BUNDLE_Entry_Type2 = The type ''{0}'' is not valid - must be {1} (allowed = {2}) Bundle_BUNDLE_Entry_Type3 = The type ''{0}'' is not valid - must be one of {1} Bundle_BUNDLE_FullUrl_Missing = Relative Reference appears inside Bundle whose entry is missing a fullUrl Bundle_BUNDLE_FullUrl_NeedVersion = Entries matching fullURL {0} should declare meta/versionId because there are version-specific references @@ -156,9 +156,9 @@ Terminology_TX_NoValid_17 = The value provided (''{0}'') is not in the value set Terminology_TX_NoValid_18 = The value provided (''{0}'') is not in the value set {1} ({2}), and a code is recommended to come from this value set){3} Terminology_TX_NoValid_2 = None of the codes provided are in the value set {0} ({1}), and a code should come from this value set unless it has no suitable code) (codes = {2}) Terminology_TX_NoValid_3 = None of the codes provided are in the value set {0} ({1}), and a code is recommended to come from this value set) (codes = {2}) -Terminology_TX_NoValid_4 = The Coding provided ({2}) is not in the value set {0}, and a code is required from this value set{1} -Terminology_TX_NoValid_5 = The Coding provided ({2}) is not in the value set {0}, and a code should come from this value set unless it has no suitable code{1} -Terminology_TX_NoValid_6 = The Coding provided ({2}) is not in the value set {0}, and a code is recommended to come from this value set{1} +Terminology_TX_NoValid_4 = The Coding provided ({2}) is not in the value set {0}, and a code is required from this value set {1} +Terminology_TX_NoValid_5 = The Coding provided ({2}) is not in the value set {0}, and a code should come from this value set unless it has no suitable code {1} +Terminology_TX_NoValid_6 = The Coding provided ({2}) is not in the value set {0}, and a code is recommended to come from this value set {1} Terminology_TX_NoValid_7 = None of the codes provided could be validated against the maximum value set {0} ({1}), (error = {2}) Terminology_TX_NoValid_8 = None of the codes provided are in the maximum value set {0} ({1}), and a code from this value set is required) (codes = {2}) Terminology_TX_NoValid_9 = The code provided could not be validated against the maximum value set {0} ({1}), (error = {2}) diff --git a/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/tests/PackageCacheTests.java b/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/tests/PackageCacheTests.java index 4f42035eb..8e8289fbd 100644 --- a/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/tests/PackageCacheTests.java +++ b/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/tests/PackageCacheTests.java @@ -37,4 +37,14 @@ public class PackageCacheTests { list = cache.listPackages(); Assertions.assertFalse(list.isEmpty()); } + + @Test + public void testPatchWildCard() throws IOException { + FilesystemPackageCacheManager cache = new FilesystemPackageCacheManager(true, ToolsVersion.TOOLS_VERSION); + cache.clear(); + Assertions.assertEquals(cache.loadPackage("hl7.fhir.us.core", "3.1.0").version(), "3.1.0"); + Assertions.assertEquals(cache.loadPackage("hl7.fhir.us.core", "3.1.1").version(), "3.1.1"); + Assertions.assertEquals(cache.loadPackage("hl7.fhir.us.core", "3.1.x").version(), "3.1.1"); + Assertions.assertEquals(cache.loadPackage("hl7.fhir.us.core", "3.0.x").version(), "3.0.1"); + } } \ No newline at end of file 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 5f641c3c9..02aee0df3 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 @@ -3943,15 +3943,17 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat private void validateContains(ValidatorHostContext hostContext, List errors, String path, ElementDefinition child, ElementDefinition context, Element resource, Element element, NodeStack stack, IdStatus idstatus) throws FHIRException { String resourceName = element.getType(); TypeRefComponent trr = null; + CommaSeparatedStringBuilder bt = new CommaSeparatedStringBuilder(); for (TypeRefComponent tr : child.getType()) { - if (tr.getCode().equals("Resource")) { + bt.append(tr.getCode()); + if (tr.getCode().equals("Resource") || tr.getCode().equals(resourceName) ) { trr = tr; break; } } stack.qualifyPath(".ofType("+resourceName+")"); if (trr == null) { - rule(errors, IssueType.INFORMATIONAL, element.line(), element.col(), stack.getLiteralPath(), false, I18nConstants.BUNDLE_BUNDLE_ENTRY_TYPE, resourceName); + rule(errors, IssueType.INFORMATIONAL, element.line(), element.col(), stack.getLiteralPath(), false, I18nConstants.BUNDLE_BUNDLE_ENTRY_TYPE, resourceName, bt.toString()); } else if (isValidResourceType(resourceName, trr)) { // special case: resource wrapper is reset if we're crossing a bundle boundary, but not otherwise ValidatorHostContext hc = null; @@ -4002,7 +4004,10 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } private boolean isValidResourceType(String type, TypeRefComponent def) { - if (!def.hasProfile()) { + if (!def.hasProfile() && def.getCode().equals("Resource")) { + return true; + } + if (def.getCode().equals(type)) { return true; } List list = new ArrayList<>(); diff --git a/pom.xml b/pom.xml index 87f56d509..6f9443f5c 100644 --- a/pom.xml +++ b/pom.xml @@ -17,7 +17,7 @@ 5.1.0 - 1.1.41 + 1.1.42-SNAPSHOT 5.6.2 3.0.0-M4 0.8.5 From 18834774545f562488659e8c6d71ed17c2a3071f Mon Sep 17 00:00:00 2001 From: Mark Iantorno Date: Thu, 17 Sep 2020 14:38:50 +0000 Subject: [PATCH 16/73] Updating test case dependency to v1.1.42 ***NO_CI*** --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6f9443f5c..1403e6bcf 100644 --- a/pom.xml +++ b/pom.xml @@ -17,7 +17,7 @@ 5.1.0 - 1.1.42-SNAPSHOT + 1.1.42 5.6.2 3.0.0-M4 0.8.5 From afa239ae8b749c147956acd1542895d3298898d4 Mon Sep 17 00:00:00 2001 From: markiantorno Date: Thu, 17 Sep 2020 15:08:40 +0000 Subject: [PATCH 17/73] Release: v5.1.12 Validator: * Fix handling resources in bundles when type is profiled * Prevent NPE resolving resource in batch * fix value set validation for primitive types when an expansion is provided, and the code system is not known Other Changes: * Package Subsystem - Support wildcars for patch version * Renderer: Don't make a column for definitions in a code system if there are none * Renderer: special case support for fr-CA language * Renderer: Prevent NPE when auto-generating narrative and an illegal resource type is encountered * FHIRPath Engine: correction for allowing boolean conversion of primitive types ***NO_CI*** --- org.hl7.fhir.convertors/pom.xml | 2 +- org.hl7.fhir.dstu2/pom.xml | 2 +- org.hl7.fhir.dstu2016may/pom.xml | 2 +- org.hl7.fhir.dstu3/pom.xml | 2 +- org.hl7.fhir.r4/pom.xml | 2 +- org.hl7.fhir.r5/pom.xml | 2 +- org.hl7.fhir.report/pom.xml | 2 +- org.hl7.fhir.utilities/pom.xml | 2 +- org.hl7.fhir.validation.cli/pom.xml | 2 +- org.hl7.fhir.validation/pom.xml | 2 +- pom.xml | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/org.hl7.fhir.convertors/pom.xml b/org.hl7.fhir.convertors/pom.xml index 1f9619f6e..4eee565d2 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 - 5.1.12-SNAPSHOT + 5.1.12 ../pom.xml diff --git a/org.hl7.fhir.dstu2/pom.xml b/org.hl7.fhir.dstu2/pom.xml index c284e5ebe..0e6b7bc81 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 - 5.1.12-SNAPSHOT + 5.1.12 ../pom.xml diff --git a/org.hl7.fhir.dstu2016may/pom.xml b/org.hl7.fhir.dstu2016may/pom.xml index 19328d407..7768ddbd6 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 - 5.1.12-SNAPSHOT + 5.1.12 ../pom.xml diff --git a/org.hl7.fhir.dstu3/pom.xml b/org.hl7.fhir.dstu3/pom.xml index 4cd27a42a..fdcaa5845 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 - 5.1.12-SNAPSHOT + 5.1.12 ../pom.xml diff --git a/org.hl7.fhir.r4/pom.xml b/org.hl7.fhir.r4/pom.xml index 5d3c135bd..ba3941f61 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 - 5.1.12-SNAPSHOT + 5.1.12 ../pom.xml diff --git a/org.hl7.fhir.r5/pom.xml b/org.hl7.fhir.r5/pom.xml index 0479bc832..493fc1049 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 - 5.1.12-SNAPSHOT + 5.1.12 ../pom.xml diff --git a/org.hl7.fhir.report/pom.xml b/org.hl7.fhir.report/pom.xml index 74d68a5d1..31d34fa4c 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 - 5.1.12-SNAPSHOT + 5.1.12 ../pom.xml diff --git a/org.hl7.fhir.utilities/pom.xml b/org.hl7.fhir.utilities/pom.xml index b51be4514..93286054d 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 - 5.1.12-SNAPSHOT + 5.1.12 ../pom.xml diff --git a/org.hl7.fhir.validation.cli/pom.xml b/org.hl7.fhir.validation.cli/pom.xml index fb3b3fcf4..b9f4abad2 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 - 5.1.12-SNAPSHOT + 5.1.12 ../pom.xml diff --git a/org.hl7.fhir.validation/pom.xml b/org.hl7.fhir.validation/pom.xml index 54f1835bc..57a235f47 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 - 5.1.12-SNAPSHOT + 5.1.12 ../pom.xml diff --git a/pom.xml b/pom.xml index 1403e6bcf..5826de914 100644 --- a/pom.xml +++ b/pom.xml @@ -13,7 +13,7 @@ each other. It is fine to bump the point version of this POM without affecting HAPI FHIR. --> - 5.1.12-SNAPSHOT + 5.1.12 5.1.0 From 4d2c81ede987daa1000a5fa90b54d4dabe391e51 Mon Sep 17 00:00:00 2001 From: markiantorno Date: Thu, 17 Sep 2020 15:26:59 +0000 Subject: [PATCH 18/73] Updating version to: 5.1.13-SNAPSHOT and incrementing test cases dependency. --- RELEASE_NOTES.md | 11 ----------- org.hl7.fhir.convertors/pom.xml | 2 +- org.hl7.fhir.dstu2/pom.xml | 2 +- org.hl7.fhir.dstu2016may/pom.xml | 2 +- org.hl7.fhir.dstu3/pom.xml | 2 +- org.hl7.fhir.r4/pom.xml | 2 +- org.hl7.fhir.r5/pom.xml | 2 +- org.hl7.fhir.report/pom.xml | 2 +- org.hl7.fhir.utilities/pom.xml | 2 +- org.hl7.fhir.validation.cli/pom.xml | 2 +- org.hl7.fhir.validation/pom.xml | 2 +- pom.xml | 2 +- 12 files changed, 11 insertions(+), 22 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 5c49d3361..e69de29bb 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,11 +0,0 @@ -Validator: -* Fix handling resources in bundles when type is profiled -* Prevent NPE resolving resource in batch -* fix value set validation for primitive types when an expansion is provided, and the code system is not known - -Other Changes: -* Package Subsystem - Support wildcars for patch version -* Renderer: Don't make a column for definitions in a code system if there are none -* Renderer: special case support for fr-CA language -* Renderer: Prevent NPE when auto-generating narrative and an illegal resource type is encountered -* FHIRPath Engine: correction for allowing boolean conversion of primitive types diff --git a/org.hl7.fhir.convertors/pom.xml b/org.hl7.fhir.convertors/pom.xml index 4eee565d2..a47706af8 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 - 5.1.12 + 5.1.13-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.dstu2/pom.xml b/org.hl7.fhir.dstu2/pom.xml index 0e6b7bc81..cc93b8ee8 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 - 5.1.12 + 5.1.13-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.dstu2016may/pom.xml b/org.hl7.fhir.dstu2016may/pom.xml index 7768ddbd6..a8148b1eb 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 - 5.1.12 + 5.1.13-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.dstu3/pom.xml b/org.hl7.fhir.dstu3/pom.xml index fdcaa5845..9220b9349 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 - 5.1.12 + 5.1.13-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.r4/pom.xml b/org.hl7.fhir.r4/pom.xml index ba3941f61..e92befd03 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 - 5.1.12 + 5.1.13-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.r5/pom.xml b/org.hl7.fhir.r5/pom.xml index 493fc1049..3989eef12 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 - 5.1.12 + 5.1.13-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.report/pom.xml b/org.hl7.fhir.report/pom.xml index 31d34fa4c..e5e80e1c4 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 - 5.1.12 + 5.1.13-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.utilities/pom.xml b/org.hl7.fhir.utilities/pom.xml index 93286054d..a07e9461e 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 - 5.1.12 + 5.1.13-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.validation.cli/pom.xml b/org.hl7.fhir.validation.cli/pom.xml index b9f4abad2..6dea47685 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 - 5.1.12 + 5.1.13-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.validation/pom.xml b/org.hl7.fhir.validation/pom.xml index 57a235f47..b5e228bfa 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 - 5.1.12 + 5.1.13-SNAPSHOT ../pom.xml diff --git a/pom.xml b/pom.xml index 5826de914..d83343043 100644 --- a/pom.xml +++ b/pom.xml @@ -13,7 +13,7 @@ each other. It is fine to bump the point version of this POM without affecting HAPI FHIR. --> - 5.1.12 + 5.1.13-SNAPSHOT 5.1.0 From 71e4b5d6e52a8456808cb546d62100fc37b8b6a0 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Mon, 21 Sep 2020 19:53:55 +1000 Subject: [PATCH 19/73] Fix bug producing nested links and producing invalid langauge rendering --- .../hl7/fhir/r5/renderers/DataRenderer.java | 92 +++++++++++++------ 1 file changed, 62 insertions(+), 30 deletions(-) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DataRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DataRenderer.java index 667bd5c15..ce468ce9f 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DataRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DataRenderer.java @@ -184,8 +184,18 @@ public class DataRenderer extends Renderer { lang = lang.substring(0, lang.indexOf("-")); } for (ConceptReferenceComponent cc : v.getCompose().getIncludeFirstRep().getConcept()) { - if (cc.getCode().equals(lang) || cc.getCode().startsWith(lang+"-")) + if (cc.getCode().equals(lang)) { l = cc; + break; + } + } + if (l == null) { + for (ConceptReferenceComponent cc : v.getCompose().getIncludeFirstRep().getConcept()) { + if (cc.getCode().startsWith(lang+"-")) { + l = cc; + break; + } + } } } if (l != null) { @@ -690,37 +700,59 @@ public class DataRenderer extends Renderer { protected void renderContactPoint(XhtmlNode x, ContactPoint contact) { if (contact != null) { - switch (contact.getSystem()) { - case EMAIL: - x.ah("mailto:"+contact.getValue()).tx(contact.getValue()); - break; - case FAX: - x.addText(displayContactPoint(contact)); - break; - case NULL: - x.addText(displayContactPoint(contact)); - break; - case OTHER: - x.addText(displayContactPoint(contact)); - break; - case PAGER: - x.addText(displayContactPoint(contact)); - break; - case PHONE: - if (contact.hasValue() && contact.getValue().startsWith("+")) { - x.ah("tel:"+contact.getValue()).tx(contact.getValue()); - } else { + if (!contact.hasSystem()) { + x.addText(displayContactPoint(contact)); + } else { + switch (contact.getSystem()) { + case EMAIL: + x.ah("mailto:"+contact.getValue()).tx(contact.getValue()); + break; + case FAX: x.addText(displayContactPoint(contact)); + break; + case NULL: + x.addText(displayContactPoint(contact)); + break; + case OTHER: + x.addText(displayContactPoint(contact)); + break; + case PAGER: + x.addText(displayContactPoint(contact)); + break; + case PHONE: + if (contact.hasValue() && contact.getValue().startsWith("+")) { + x.ah("tel:"+contact.getValue()).tx(contact.getValue()); + } else { + x.addText(displayContactPoint(contact)); + } + break; + case SMS: + x.addText(displayContactPoint(contact)); + break; + case URL: + x.ah(contact.getValue()).tx(contact.getValue()); + break; + default: + break; + } + } + } + } + + protected void displayContactPoint(XhtmlNode p, ContactPoint c) { + if (c != null) { + if (c.getSystem() == ContactPointSystem.PHONE) { + p.tx("Phone: "+c.getValue()); + } else if (c.getSystem() == ContactPointSystem.FAX) { + p.tx("Fax: "+c.getValue()); + } else if (c.getSystem() == ContactPointSystem.EMAIL) { + p.tx(c.getValue()); + } else if (c.getSystem() == ContactPointSystem.URL) { + if (c.getValue().length() > 30) { + p.addText(c.getValue().substring(0, 30)+"..."); + } else { + p.addText(c.getValue()); } - break; - case SMS: - x.addText(displayContactPoint(contact)); - break; - case URL: - x.ah(contact.getValue()).tx(contact.getValue()); - break; - default: - break; } } } From 17ed666fef2568e6cd51cefdf005da66ae6d8637 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Mon, 21 Sep 2020 19:54:45 +1000 Subject: [PATCH 20/73] fix bug with nested links --- .../java/org/hl7/fhir/r5/renderers/ProfileDrivenRenderer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ProfileDrivenRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ProfileDrivenRenderer.java index 359432b46..5d1f0797f 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ProfileDrivenRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ProfileDrivenRenderer.java @@ -488,7 +488,7 @@ public class ProfileDrivenRenderer extends ResourceRenderer { renderAddress(x, (Address) e); return true; } else if (e instanceof ContactPoint) { - renderContactPoint(x, (ContactPoint) e); + displayContactPoint(x, (ContactPoint) e); return true; } else if (e instanceof Timing) { renderTiming(x, (Timing) e); @@ -530,7 +530,7 @@ public class ProfileDrivenRenderer extends ResourceRenderer { boolean first = true; for (ContactPoint c : cd.getTelecom()) { if (first) first = false; else x.tx(","); - renderContactPoint(x, c); + displayContactPoint(x, c); } return true; } else if (e instanceof Range) { From eba38941d385b2d8dc52829346e74e4eada92f90 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Mon, 21 Sep 2020 19:55:51 +1000 Subject: [PATCH 21/73] fix resource leaks --- .../java/org/hl7/fhir/utilities/Utilities.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) 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 2015c3e22..82d06017a 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 @@ -47,6 +47,8 @@ import java.math.RoundingMode; import java.net.URLDecoder; import java.net.URLEncoder; import java.nio.channels.FileChannel; +import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.Paths; import java.time.Duration; import java.util.ArrayList; @@ -320,13 +322,13 @@ public class Utilities { destFile.createNewFile(); } - FileChannel source = null; - FileChannel destination = null; + FileInputStream source = null; + FileOutputStream destination = null; try { - source = new FileInputStream(sourceFile).getChannel(); - destination = new FileOutputStream(destFile).getChannel(); - destination.transferFrom(source, 0, source.size()); + source = new FileInputStream(sourceFile); + destination = new FileOutputStream(destFile); + destination.getChannel().transferFrom(source.getChannel(), 0, source.getChannel().size()); } finally { if (source != null) { source.close(); @@ -398,8 +400,8 @@ public class Utilities { clearDirectory(fh.getAbsolutePath()); fh.delete(); } + } } - } } } } From d07966e4226890c110617020a6eda56ab101bd92 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Tue, 22 Sep 2020 02:14:23 +1000 Subject: [PATCH 22/73] remove spaces from generated tel: links --- .../src/main/java/org/hl7/fhir/r5/renderers/DataRenderer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DataRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DataRenderer.java index ce468ce9f..ac04d007d 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DataRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DataRenderer.java @@ -721,7 +721,7 @@ public class DataRenderer extends Renderer { break; case PHONE: if (contact.hasValue() && contact.getValue().startsWith("+")) { - x.ah("tel:"+contact.getValue()).tx(contact.getValue()); + x.ah("tel:"+contact.getValue().replace(" ", "")).tx(contact.getValue()); } else { x.addText(displayContactPoint(contact)); } From a15be7d31405fc50b0a276eac0c301be55f97a7f Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Tue, 22 Sep 2020 02:14:55 +1000 Subject: [PATCH 23/73] allow links when ok --- .../hl7/fhir/r5/renderers/ProfileDrivenRenderer.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ProfileDrivenRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ProfileDrivenRenderer.java index 5d1f0797f..155e8bbc0 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ProfileDrivenRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ProfileDrivenRenderer.java @@ -488,7 +488,11 @@ public class ProfileDrivenRenderer extends ResourceRenderer { renderAddress(x, (Address) e); return true; } else if (e instanceof ContactPoint) { - displayContactPoint(x, (ContactPoint) e); + if (allowLinks) { + renderContactPoint(x, (ContactPoint) e); + } else { + displayContactPoint(x, (ContactPoint) e); + } return true; } else if (e instanceof Timing) { renderTiming(x, (Timing) e); @@ -530,7 +534,11 @@ public class ProfileDrivenRenderer extends ResourceRenderer { boolean first = true; for (ContactPoint c : cd.getTelecom()) { if (first) first = false; else x.tx(","); - displayContactPoint(x, c); + if (allowLinks) { + renderContactPoint(x, c); + } else { + displayContactPoint(x, c); + } } return true; } else if (e instanceof Range) { From 3c0b20eb16128252934d6f2d0101a34a9cf32d7d Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Tue, 22 Sep 2020 02:34:04 +1000 Subject: [PATCH 24/73] Add quality code (yet to turn it on) --- .../hl7/fhir/utilities/xhtml/XhtmlNode.java | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlNode.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlNode.java index 9a0d0cba7..e561009f2 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlNode.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlNode.java @@ -90,6 +90,9 @@ public class XhtmlNode implements IBaseXhtml { private List childNodes = new ArrayList(); private String content; private boolean notPretty; + private boolean inPara; + private boolean inLink; + public XhtmlNode() { super(); @@ -144,7 +147,7 @@ public class XhtmlNode implements IBaseXhtml { return this; } - public void validate(List errors, String path, boolean inResource, boolean inPara) { + public void validate(List errors, String path, boolean inResource, boolean inPara, boolean inLink) { if (nodeType == NodeType.Element || nodeType == NodeType.Document) { path = Utilities.noString(path) ? name : path+"/"+name; if (inResource) { @@ -172,13 +175,19 @@ public class XhtmlNode implements IBaseXhtml { if (inPara && Utilities.existsInList(name, "div", "blockquote", "table", "ol", "ul", "p")) { errors.add("Error at "+path+": Found "+name+" inside an html paragraph"); } + if (inLink && Utilities.existsInList(name, "a")) { + errors.add("Error at "+path+": Found an inside an paragraph"); + } if (childNodes != null) { if ("p".equals(name)) { inPara = true; } + if ("a".equals(name)) { + inLink = true; + } for (XhtmlNode child : childNodes) { - child.validate(errors, path, inResource, inPara); + child.validate(errors, path, inResource, inPara, inLink); } } } @@ -191,8 +200,20 @@ public class XhtmlNode implements IBaseXhtml { throw new Error("Wrong node type - node is "+nodeType.toString()+" ('"+getName()+"/"+getContent()+"')"); } +// if (inPara && name.equals("p")) { +// throw new FHIRException("nested Para"); +// } +// if (inLink && name.equals("a")) { +// throw new FHIRException("Nested Link"); +// } XhtmlNode node = new XhtmlNode(NodeType.Element); node.setName(name); + if (inPara || name.equals("p")) { + node.inPara = true; + } + if (inLink || name.equals("a")) { + node.inLink = true; + } childNodes.add(node); return node; } @@ -203,6 +224,12 @@ public class XhtmlNode implements IBaseXhtml { if (!(nodeType == NodeType.Element || nodeType == NodeType.Document)) throw new Error("Wrong node type. is "+nodeType.toString()); XhtmlNode node = new XhtmlNode(NodeType.Element); + if (inPara || name.equals("p")) { + node.inPara = true; + } + if (inLink || name.equals("a")) { + node.inLink = true; + } node.setName(name); childNodes.add(index, node); return node; From 9c09320530aec59493814238852786584999bcd5 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Tue, 22 Sep 2020 04:09:27 +1000 Subject: [PATCH 25/73] release notes --- RELEASE_NOTES.md | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 5c49d3361..a27e809f7 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,11 +1,6 @@ Validator: -* Fix handling resources in bundles when type is profiled -* Prevent NPE resolving resource in batch -* fix value set validation for primitive types when an expansion is provided, and the code system is not known +* No Changes Other Changes: -* Package Subsystem - Support wildcars for patch version -* Renderer: Don't make a column for definitions in a code system if there are none -* Renderer: special case support for fr-CA language -* Renderer: Prevent NPE when auto-generating narrative and an illegal resource type is encountered -* FHIRPath Engine: correction for allowing boolean conversion of primitive types +* Various minor improvements to rendering code + From 268bb8cde75c56d09ad6877729ada4e1790e477c Mon Sep 17 00:00:00 2001 From: markiantorno Date: Mon, 21 Sep 2020 19:24:29 +0000 Subject: [PATCH 26/73] Release: v5.1.13 Validator: * No Changes Other Changes: * Various minor improvements to rendering code ***NO_CI*** --- org.hl7.fhir.convertors/pom.xml | 2 +- org.hl7.fhir.dstu2/pom.xml | 2 +- org.hl7.fhir.dstu2016may/pom.xml | 2 +- org.hl7.fhir.dstu3/pom.xml | 2 +- org.hl7.fhir.r4/pom.xml | 2 +- org.hl7.fhir.r5/pom.xml | 2 +- org.hl7.fhir.report/pom.xml | 2 +- org.hl7.fhir.utilities/pom.xml | 2 +- org.hl7.fhir.validation.cli/pom.xml | 2 +- org.hl7.fhir.validation/pom.xml | 2 +- pom.xml | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/org.hl7.fhir.convertors/pom.xml b/org.hl7.fhir.convertors/pom.xml index a47706af8..d4915457d 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 - 5.1.13-SNAPSHOT + 5.1.13 ../pom.xml diff --git a/org.hl7.fhir.dstu2/pom.xml b/org.hl7.fhir.dstu2/pom.xml index cc93b8ee8..4e2fdaca3 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 - 5.1.13-SNAPSHOT + 5.1.13 ../pom.xml diff --git a/org.hl7.fhir.dstu2016may/pom.xml b/org.hl7.fhir.dstu2016may/pom.xml index a8148b1eb..31d9729fa 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 - 5.1.13-SNAPSHOT + 5.1.13 ../pom.xml diff --git a/org.hl7.fhir.dstu3/pom.xml b/org.hl7.fhir.dstu3/pom.xml index 9220b9349..3ec7b4233 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 - 5.1.13-SNAPSHOT + 5.1.13 ../pom.xml diff --git a/org.hl7.fhir.r4/pom.xml b/org.hl7.fhir.r4/pom.xml index e92befd03..0f65e810d 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 - 5.1.13-SNAPSHOT + 5.1.13 ../pom.xml diff --git a/org.hl7.fhir.r5/pom.xml b/org.hl7.fhir.r5/pom.xml index 3989eef12..d1c543490 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 - 5.1.13-SNAPSHOT + 5.1.13 ../pom.xml diff --git a/org.hl7.fhir.report/pom.xml b/org.hl7.fhir.report/pom.xml index e5e80e1c4..17c19414b 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 - 5.1.13-SNAPSHOT + 5.1.13 ../pom.xml diff --git a/org.hl7.fhir.utilities/pom.xml b/org.hl7.fhir.utilities/pom.xml index a07e9461e..c5f236a64 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 - 5.1.13-SNAPSHOT + 5.1.13 ../pom.xml diff --git a/org.hl7.fhir.validation.cli/pom.xml b/org.hl7.fhir.validation.cli/pom.xml index 6dea47685..cdf5b5a2a 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 - 5.1.13-SNAPSHOT + 5.1.13 ../pom.xml diff --git a/org.hl7.fhir.validation/pom.xml b/org.hl7.fhir.validation/pom.xml index b5e228bfa..7e811ba8f 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 - 5.1.13-SNAPSHOT + 5.1.13 ../pom.xml diff --git a/pom.xml b/pom.xml index 41bf97232..9cdc36a5e 100644 --- a/pom.xml +++ b/pom.xml @@ -13,7 +13,7 @@ each other. It is fine to bump the point version of this POM without affecting HAPI FHIR. --> - 5.1.13-SNAPSHOT + 5.1.13 5.1.0 From 5e3b51e2863f05f7da9725fcfc3f721c27ddbb4a Mon Sep 17 00:00:00 2001 From: markiantorno Date: Mon, 21 Sep 2020 19:41:08 +0000 Subject: [PATCH 27/73] Updating version to: 5.1.14-SNAPSHOT and incrementing test cases dependency. --- RELEASE_NOTES.md | 6 ------ org.hl7.fhir.convertors/pom.xml | 2 +- org.hl7.fhir.dstu2/pom.xml | 2 +- org.hl7.fhir.dstu2016may/pom.xml | 2 +- org.hl7.fhir.dstu3/pom.xml | 2 +- org.hl7.fhir.r4/pom.xml | 2 +- org.hl7.fhir.r5/pom.xml | 2 +- org.hl7.fhir.report/pom.xml | 2 +- org.hl7.fhir.utilities/pom.xml | 2 +- org.hl7.fhir.validation.cli/pom.xml | 2 +- org.hl7.fhir.validation/pom.xml | 2 +- pom.xml | 2 +- 12 files changed, 11 insertions(+), 17 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index a27e809f7..e69de29bb 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,6 +0,0 @@ -Validator: -* No Changes - -Other Changes: -* Various minor improvements to rendering code - diff --git a/org.hl7.fhir.convertors/pom.xml b/org.hl7.fhir.convertors/pom.xml index d4915457d..cee272fa6 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 - 5.1.13 + 5.1.14-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.dstu2/pom.xml b/org.hl7.fhir.dstu2/pom.xml index 4e2fdaca3..b851cfc3b 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 - 5.1.13 + 5.1.14-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.dstu2016may/pom.xml b/org.hl7.fhir.dstu2016may/pom.xml index 31d9729fa..4948e25d2 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 - 5.1.13 + 5.1.14-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.dstu3/pom.xml b/org.hl7.fhir.dstu3/pom.xml index 3ec7b4233..a0d999cae 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 - 5.1.13 + 5.1.14-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.r4/pom.xml b/org.hl7.fhir.r4/pom.xml index 0f65e810d..21841a440 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 - 5.1.13 + 5.1.14-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.r5/pom.xml b/org.hl7.fhir.r5/pom.xml index d1c543490..abbebd467 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 - 5.1.13 + 5.1.14-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.report/pom.xml b/org.hl7.fhir.report/pom.xml index 17c19414b..90e45a22b 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 - 5.1.13 + 5.1.14-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.utilities/pom.xml b/org.hl7.fhir.utilities/pom.xml index c5f236a64..382f03387 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 - 5.1.13 + 5.1.14-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.validation.cli/pom.xml b/org.hl7.fhir.validation.cli/pom.xml index cdf5b5a2a..1fd5a71b2 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 - 5.1.13 + 5.1.14-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.validation/pom.xml b/org.hl7.fhir.validation/pom.xml index 7e811ba8f..83a963927 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 - 5.1.13 + 5.1.14-SNAPSHOT ../pom.xml diff --git a/pom.xml b/pom.xml index 9cdc36a5e..a0a6b5c09 100644 --- a/pom.xml +++ b/pom.xml @@ -13,7 +13,7 @@ each other. It is fine to bump the point version of this POM without affecting HAPI FHIR. --> - 5.1.13 + 5.1.14-SNAPSHOT 5.1.0 From 58b6969544967d9ff46fd4691efecbc964bf68c9 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Tue, 22 Sep 2020 22:00:15 +1000 Subject: [PATCH 28/73] Ensure "I" flag in profile table representation is not used for underlying infrastructural constraints that exist everywhere --- .../fhir/r5/conformance/ProfileUtilities.java | 40 +++++++++++++++++-- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfileUtilities.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfileUtilities.java index 970bac706..532fef47d 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfileUtilities.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfileUtilities.java @@ -3812,7 +3812,7 @@ public class ProfileUtilities extends TranslatingUtilities { if (element != null && element.getIsSummary()) { checkForNoChange(element.getIsSummaryElement(), gc.addStyledText(translate("sd.table", "This element is included in summaries"), "\u03A3", null, null, null, false)); } - if (element != null && (!element.getConstraint().isEmpty() || !element.getCondition().isEmpty())) { + if (element != null && (hasNonBaseConstraints(element.getConstraint()) || hasNonBaseConditions(element.getCondition()))) { gc.addStyledText(translate("sd.table", "This element has or is affected by some invariants ("+listConstraintsAndConditions(element)+")"), "I", null, null, null, false); } @@ -3860,7 +3860,8 @@ public class ProfileUtilities extends TranslatingUtilities { return res; } - private Cell addCell(Row row, Cell cell) { + + private Cell addCell(Row row, Cell cell) { row.getCells().add(cell); return (cell); } @@ -3869,18 +3870,49 @@ public class ProfileUtilities extends TranslatingUtilities { return app == null ? src : src + app; } + private boolean hasNonBaseConditions(List conditions) { + for (IdType c : conditions) { + if (!isBaseCondition(c)) { + return true; + } + } + return false; + } + + + private boolean hasNonBaseConstraints(List constraints) { + for (ElementDefinitionConstraintComponent c : constraints) { + if (!isBaseConstraint(c)) { + return true; + } + } + return false; + } private String listConstraintsAndConditions(ElementDefinition element) { CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(); for (ElementDefinitionConstraintComponent con : element.getConstraint()) { - b.append(con.getKey()); + if (!isBaseConstraint(con)) { + b.append(con.getKey()); + } } for (IdType id : element.getCondition()) { - b.append(id.asStringValue()); + if (!isBaseCondition(id)) { + b.append(id.asStringValue()); + } } return b.toString(); } + private boolean isBaseCondition(IdType c) { + String key = c.asStringValue(); + return key.startsWith("ele-") || key.startsWith("res-") || key.startsWith("ext-") || key.startsWith("dom-") || key.startsWith("dr-"); + } + + private boolean isBaseConstraint(ElementDefinitionConstraintComponent con) { + String key = con.getKey(); + return key.startsWith("ele-") || key.startsWith("res-") || key.startsWith("ext-") || key.startsWith("dom-") || key.startsWith("dr-"); + } private void makeChoiceRows(List subRows, ElementDefinition element, HierarchicalTableGenerator gen, String corePath, String profileBaseFileName) { // create a child for each choice From 278697f72bf1cd9fa7353f82fb8f0e27746be902 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Tue, 22 Sep 2020 22:00:37 +1000 Subject: [PATCH 29/73] render multiple values for properties if they exist --- .../fhir/r5/renderers/CodeSystemRenderer.java | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/CodeSystemRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/CodeSystemRenderer.java index 028b2c68a..7af63b922 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/CodeSystemRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/CodeSystemRenderer.java @@ -416,15 +416,17 @@ public class CodeSystemRenderer extends TerminologyRenderer { for (PropertyComponent pc : properties) { td = tr.td(); boolean first = true; - ConceptPropertyComponent pcv = CodeSystemUtilities.getProperty(c, pc.getCode()); - if (pcv != null && pcv.hasValue()) { - if (first) first = false; else td.addText(", "); - if (pcv.hasValueCoding()) { - td.addText(pcv.getValueCoding().getCode()); - } else if (pcv.hasValueStringType() && Utilities.isAbsoluteUrl(pcv.getValue().primitiveValue())) { - td.ah(pcv.getValue().primitiveValue()).tx(pcv.getValue().primitiveValue()); - } else { - td.addText(pcv.getValue().primitiveValue()); + List pcvl = CodeSystemUtilities.getPropertyValues(c, pc.getCode()); + for (ConceptPropertyComponent pcv : pcvl) { + if (pcv.hasValue()) { + if (first) first = false; else td.addText(", "); + if (pcv.hasValueCoding()) { + td.addText(pcv.getValueCoding().getCode()); + } else if (pcv.hasValueStringType() && Utilities.isAbsoluteUrl(pcv.getValue().primitiveValue())) { + td.ah(pcv.getValue().primitiveValue()).tx(pcv.getValue().primitiveValue()); + } else { + td.addText(pcv.getValue().primitiveValue()); + } } } } From 5ada654ca2594585d1ee948829af70803c669838 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Tue, 22 Sep 2020 22:01:02 +1000 Subject: [PATCH 30/73] fix for npe --- .../org/hl7/fhir/r5/renderers/DataRenderer.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DataRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DataRenderer.java index ac04d007d..2033956f9 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DataRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DataRenderer.java @@ -251,12 +251,12 @@ public class DataRenderer extends Renderer { } else { return "No display for "+b.fhirType(); } - } public String display(DataType type) { - if (type.isEmpty()) + if (type == null || type.isEmpty()) { return ""; + } if (type instanceof Coding) { return displayCoding((Coding) type); @@ -354,7 +354,6 @@ public class DataRenderer extends Renderer { } else { x.tx("No display for "+type.fhirType()); } - } private void renderReference(XhtmlNode x, Reference ref) { @@ -368,15 +367,17 @@ public class DataRenderer extends Renderer { } public void renderDateTime(XhtmlNode x, Base e) { - if (e.hasPrimitiveValue()) + if (e.hasPrimitiveValue()) { x.addText(((DateTimeType) e).toHumanDisplay()); + } } protected void renderUri(XhtmlNode x, UriType uri) { - if (uri.getValue().startsWith("mailto:")) + if (uri.getValue().startsWith("mailto:")) { x.ah(uri.getValue()).addText(uri.getValue().substring(7)); - else + } else { x.ah(uri.getValue()).addText(uri.getValue()); + } } protected void renderUri(XhtmlNode x, UriType uri, String path, String id) { @@ -782,7 +783,6 @@ public class DataRenderer extends Renderer { } } - protected String displayQuantity(Quantity q) { StringBuilder s = new StringBuilder(); From 6fb4610b5fd4640e3a863374b9ea381f9788ec70 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Tue, 22 Sep 2020 22:01:37 +1000 Subject: [PATCH 31/73] fix for use of "current" as version --- .../main/java/org/hl7/fhir/utilities/VersionUtilities.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/VersionUtilities.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/VersionUtilities.java index c90530f2a..83e69ed40 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/VersionUtilities.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/VersionUtilities.java @@ -181,6 +181,10 @@ public class VersionUtilities { public static String getMajMin(String version) { if (version == null) return null; + + if ("current".equals(version)) { + return CURRENT_VERSION; + } if (Utilities.charCount(version, '.') == 1) { String[] p = version.split("\\."); From cc64eb7fea0a5d06e7447d4d4bce26ad90dc77cb Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Tue, 22 Sep 2020 22:02:01 +1000 Subject: [PATCH 32/73] fix bad package URLs as they are loaded --- .../src/main/java/org/hl7/fhir/utilities/cache/NpmPackage.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/NpmPackage.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/NpmPackage.java index b87b60818..f32ef1380 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/NpmPackage.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/NpmPackage.java @@ -814,7 +814,7 @@ public class NpmPackage { public String getWebLocation() { if (npm.has("url")) { - return npm.get("url").getAsString(); + return PackageHacker.fixPackageUrl(npm.get("url").getAsString()); } else { return JSONUtil.str(npm, "canonical"); } From 9d0fe1a0815b0758baa9f58fa4fb5c032eea3172 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Wed, 23 Sep 2020 03:48:25 +1000 Subject: [PATCH 33/73] RELEASE_NOTES.md --- RELEASE_NOTES.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index e69de29bb..de602e213 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -0,0 +1,9 @@ +Validator: +* no changes with impact + +Other code changes: +* Ensure "I" flag in profile table representation is not used just for infrastructural constraints +* Render multiple values for properties in CodeSystems if they exist +* Fix for npe rendering resources based on profiles +* fix for use of "current" as version +* hack for past bad package URLs \ No newline at end of file From b8370f7e61ec45e60b74c72d85a3e869d95f2a8a Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Wed, 23 Sep 2020 06:17:45 +1000 Subject: [PATCH 34/73] various minor fixes (#353) * Ensure "I" flag in profile table representation is not used for underlying infrastructural constraints that exist everywhere * render multiple values for properties if they exist * fix for npe * fix for use of "current" as version * fix bad package URLs as they are loaded * RELEASE_NOTES.md --- RELEASE_NOTES.md | 9 +++++ .../fhir/r5/conformance/ProfileUtilities.java | 40 +++++++++++++++++-- .../fhir/r5/renderers/CodeSystemRenderer.java | 20 +++++----- .../hl7/fhir/r5/renderers/DataRenderer.java | 14 +++---- .../hl7/fhir/utilities/VersionUtilities.java | 4 ++ .../hl7/fhir/utilities/cache/NpmPackage.java | 2 +- 6 files changed, 68 insertions(+), 21 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index e69de29bb..de602e213 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -0,0 +1,9 @@ +Validator: +* no changes with impact + +Other code changes: +* Ensure "I" flag in profile table representation is not used just for infrastructural constraints +* Render multiple values for properties in CodeSystems if they exist +* Fix for npe rendering resources based on profiles +* fix for use of "current" as version +* hack for past bad package URLs \ No newline at end of file diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfileUtilities.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfileUtilities.java index 970bac706..532fef47d 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfileUtilities.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfileUtilities.java @@ -3812,7 +3812,7 @@ public class ProfileUtilities extends TranslatingUtilities { if (element != null && element.getIsSummary()) { checkForNoChange(element.getIsSummaryElement(), gc.addStyledText(translate("sd.table", "This element is included in summaries"), "\u03A3", null, null, null, false)); } - if (element != null && (!element.getConstraint().isEmpty() || !element.getCondition().isEmpty())) { + if (element != null && (hasNonBaseConstraints(element.getConstraint()) || hasNonBaseConditions(element.getCondition()))) { gc.addStyledText(translate("sd.table", "This element has or is affected by some invariants ("+listConstraintsAndConditions(element)+")"), "I", null, null, null, false); } @@ -3860,7 +3860,8 @@ public class ProfileUtilities extends TranslatingUtilities { return res; } - private Cell addCell(Row row, Cell cell) { + + private Cell addCell(Row row, Cell cell) { row.getCells().add(cell); return (cell); } @@ -3869,18 +3870,49 @@ public class ProfileUtilities extends TranslatingUtilities { return app == null ? src : src + app; } + private boolean hasNonBaseConditions(List conditions) { + for (IdType c : conditions) { + if (!isBaseCondition(c)) { + return true; + } + } + return false; + } + + + private boolean hasNonBaseConstraints(List constraints) { + for (ElementDefinitionConstraintComponent c : constraints) { + if (!isBaseConstraint(c)) { + return true; + } + } + return false; + } private String listConstraintsAndConditions(ElementDefinition element) { CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(); for (ElementDefinitionConstraintComponent con : element.getConstraint()) { - b.append(con.getKey()); + if (!isBaseConstraint(con)) { + b.append(con.getKey()); + } } for (IdType id : element.getCondition()) { - b.append(id.asStringValue()); + if (!isBaseCondition(id)) { + b.append(id.asStringValue()); + } } return b.toString(); } + private boolean isBaseCondition(IdType c) { + String key = c.asStringValue(); + return key.startsWith("ele-") || key.startsWith("res-") || key.startsWith("ext-") || key.startsWith("dom-") || key.startsWith("dr-"); + } + + private boolean isBaseConstraint(ElementDefinitionConstraintComponent con) { + String key = con.getKey(); + return key.startsWith("ele-") || key.startsWith("res-") || key.startsWith("ext-") || key.startsWith("dom-") || key.startsWith("dr-"); + } private void makeChoiceRows(List subRows, ElementDefinition element, HierarchicalTableGenerator gen, String corePath, String profileBaseFileName) { // create a child for each choice diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/CodeSystemRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/CodeSystemRenderer.java index 028b2c68a..7af63b922 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/CodeSystemRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/CodeSystemRenderer.java @@ -416,15 +416,17 @@ public class CodeSystemRenderer extends TerminologyRenderer { for (PropertyComponent pc : properties) { td = tr.td(); boolean first = true; - ConceptPropertyComponent pcv = CodeSystemUtilities.getProperty(c, pc.getCode()); - if (pcv != null && pcv.hasValue()) { - if (first) first = false; else td.addText(", "); - if (pcv.hasValueCoding()) { - td.addText(pcv.getValueCoding().getCode()); - } else if (pcv.hasValueStringType() && Utilities.isAbsoluteUrl(pcv.getValue().primitiveValue())) { - td.ah(pcv.getValue().primitiveValue()).tx(pcv.getValue().primitiveValue()); - } else { - td.addText(pcv.getValue().primitiveValue()); + List pcvl = CodeSystemUtilities.getPropertyValues(c, pc.getCode()); + for (ConceptPropertyComponent pcv : pcvl) { + if (pcv.hasValue()) { + if (first) first = false; else td.addText(", "); + if (pcv.hasValueCoding()) { + td.addText(pcv.getValueCoding().getCode()); + } else if (pcv.hasValueStringType() && Utilities.isAbsoluteUrl(pcv.getValue().primitiveValue())) { + td.ah(pcv.getValue().primitiveValue()).tx(pcv.getValue().primitiveValue()); + } else { + td.addText(pcv.getValue().primitiveValue()); + } } } } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DataRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DataRenderer.java index ac04d007d..2033956f9 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DataRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DataRenderer.java @@ -251,12 +251,12 @@ public class DataRenderer extends Renderer { } else { return "No display for "+b.fhirType(); } - } public String display(DataType type) { - if (type.isEmpty()) + if (type == null || type.isEmpty()) { return ""; + } if (type instanceof Coding) { return displayCoding((Coding) type); @@ -354,7 +354,6 @@ public class DataRenderer extends Renderer { } else { x.tx("No display for "+type.fhirType()); } - } private void renderReference(XhtmlNode x, Reference ref) { @@ -368,15 +367,17 @@ public class DataRenderer extends Renderer { } public void renderDateTime(XhtmlNode x, Base e) { - if (e.hasPrimitiveValue()) + if (e.hasPrimitiveValue()) { x.addText(((DateTimeType) e).toHumanDisplay()); + } } protected void renderUri(XhtmlNode x, UriType uri) { - if (uri.getValue().startsWith("mailto:")) + if (uri.getValue().startsWith("mailto:")) { x.ah(uri.getValue()).addText(uri.getValue().substring(7)); - else + } else { x.ah(uri.getValue()).addText(uri.getValue()); + } } protected void renderUri(XhtmlNode x, UriType uri, String path, String id) { @@ -782,7 +783,6 @@ public class DataRenderer extends Renderer { } } - protected String displayQuantity(Quantity q) { StringBuilder s = new StringBuilder(); diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/VersionUtilities.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/VersionUtilities.java index c90530f2a..83e69ed40 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/VersionUtilities.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/VersionUtilities.java @@ -181,6 +181,10 @@ public class VersionUtilities { public static String getMajMin(String version) { if (version == null) return null; + + if ("current".equals(version)) { + return CURRENT_VERSION; + } if (Utilities.charCount(version, '.') == 1) { String[] p = version.split("\\."); diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/NpmPackage.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/NpmPackage.java index b87b60818..f32ef1380 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/NpmPackage.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/NpmPackage.java @@ -814,7 +814,7 @@ public class NpmPackage { public String getWebLocation() { if (npm.has("url")) { - return npm.get("url").getAsString(); + return PackageHacker.fixPackageUrl(npm.get("url").getAsString()); } else { return JSONUtil.str(npm, "canonical"); } From 8eeffb89795b86a126cfeb6f3623dcb4070b0623 Mon Sep 17 00:00:00 2001 From: Mark Iantorno Date: Wed, 23 Sep 2020 07:01:24 -0400 Subject: [PATCH 35/73] fixed conversion for Device (#355) --- .../convertors/VersionConvertor_30_40.java | 87 +----- .../convertors/conv30_40/Device30_40.java | 258 ++++++++++++++++++ .../convertors/conv30_40/Device30_40Test.java | 43 +++ .../src/test/resources/0_device_30.json | 13 + .../src/test/resources/0_device_40.json | 20 ++ .../src/test/resources/1_device_30.json | 13 + .../src/test/resources/1_device_40.json | 20 ++ 7 files changed, 370 insertions(+), 84 deletions(-) create mode 100644 org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv30_40/Device30_40.java create mode 100644 org.hl7.fhir.convertors/src/test/java/org/hl7/fhir/convertors/conv30_40/Device30_40Test.java create mode 100644 org.hl7.fhir.convertors/src/test/resources/0_device_30.json create mode 100644 org.hl7.fhir.convertors/src/test/resources/0_device_40.json create mode 100644 org.hl7.fhir.convertors/src/test/resources/1_device_30.json create mode 100644 org.hl7.fhir.convertors/src/test/resources/1_device_40.json diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/VersionConvertor_30_40.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/VersionConvertor_30_40.java index 4837eeb0f..af922aba6 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/VersionConvertor_30_40.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/VersionConvertor_30_40.java @@ -4,90 +4,7 @@ import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; -import org.hl7.fhir.convertors.conv30_40.Account30_40; -import org.hl7.fhir.convertors.conv30_40.ActivityDefinition30_40; -import org.hl7.fhir.convertors.conv30_40.AllergyIntolerance30_40; -import org.hl7.fhir.convertors.conv30_40.Appointment30_40; -import org.hl7.fhir.convertors.conv30_40.AppointmentResponse30_40; -import org.hl7.fhir.convertors.conv30_40.AuditEvent30_40; -import org.hl7.fhir.convertors.conv30_40.Basic30_40; -import org.hl7.fhir.convertors.conv30_40.Binary30_40; -import org.hl7.fhir.convertors.conv30_40.BodySite30_40; -import org.hl7.fhir.convertors.conv30_40.Bundle30_40; -import org.hl7.fhir.convertors.conv30_40.CapabilityStatement30_40; -import org.hl7.fhir.convertors.conv30_40.CarePlan30_40; -import org.hl7.fhir.convertors.conv30_40.CareTeam30_40; -import org.hl7.fhir.convertors.conv30_40.ClinicalImpression30_40; -import org.hl7.fhir.convertors.conv30_40.CodeSystem30_40; -import org.hl7.fhir.convertors.conv30_40.Communication30_40; -import org.hl7.fhir.convertors.conv30_40.CompartmentDefinition30_40; -import org.hl7.fhir.convertors.conv30_40.Composition30_40; -import org.hl7.fhir.convertors.conv30_40.ConceptMap30_40; -import org.hl7.fhir.convertors.conv30_40.Condition30_40; -import org.hl7.fhir.convertors.conv30_40.Consent30_40; -import org.hl7.fhir.convertors.conv30_40.Coverage30_40; -import org.hl7.fhir.convertors.conv30_40.DataElement30_40; -import org.hl7.fhir.convertors.conv30_40.DetectedIssue30_40; -import org.hl7.fhir.convertors.conv30_40.DeviceUseStatement30_40; -import org.hl7.fhir.convertors.conv30_40.DiagnosticReport30_40; -import org.hl7.fhir.convertors.conv30_40.DocumentReference30_40; -import org.hl7.fhir.convertors.conv30_40.Encounter30_40; -import org.hl7.fhir.convertors.conv30_40.Endpoint30_40; -import org.hl7.fhir.convertors.conv30_40.EpisodeOfCare30_40; -import org.hl7.fhir.convertors.conv30_40.ExpansionProfile30_40; -import org.hl7.fhir.convertors.conv30_40.FamilyMemberHistory30_40; -import org.hl7.fhir.convertors.conv30_40.Flag30_40; -import org.hl7.fhir.convertors.conv30_40.Goal30_40; -import org.hl7.fhir.convertors.conv30_40.GraphDefinition30_40; -import org.hl7.fhir.convertors.conv30_40.Group30_40; -import org.hl7.fhir.convertors.conv30_40.HealthcareService30_40; -import org.hl7.fhir.convertors.conv30_40.ImagingStudy30_40; -import org.hl7.fhir.convertors.conv30_40.Immunization30_40; -import org.hl7.fhir.convertors.conv30_40.ImplementationGuide30_40; -import org.hl7.fhir.convertors.conv30_40.Library30_40; -import org.hl7.fhir.convertors.conv30_40.Linkage30_40; -import org.hl7.fhir.convertors.conv30_40.List30_40; -import org.hl7.fhir.convertors.conv30_40.Location30_40; -import org.hl7.fhir.convertors.conv30_40.Media30_40; -import org.hl7.fhir.convertors.conv30_40.Medication30_40; -import org.hl7.fhir.convertors.conv30_40.MedicationAdministration30_40; -import org.hl7.fhir.convertors.conv30_40.MedicationDispense30_40; -import org.hl7.fhir.convertors.conv30_40.MedicationRequest30_40; -import org.hl7.fhir.convertors.conv30_40.MedicationStatement30_40; -import org.hl7.fhir.convertors.conv30_40.MessageDefinition30_40; -import org.hl7.fhir.convertors.conv30_40.MessageHeader30_40; -import org.hl7.fhir.convertors.conv30_40.NamingSystem30_40; -import org.hl7.fhir.convertors.conv30_40.Observation30_40; -import org.hl7.fhir.convertors.conv30_40.OperationDefinition30_40; -import org.hl7.fhir.convertors.conv30_40.OperationOutcome30_40; -import org.hl7.fhir.convertors.conv30_40.Organization30_40; -import org.hl7.fhir.convertors.conv30_40.Parameters30_40; -import org.hl7.fhir.convertors.conv30_40.Patient30_40; -import org.hl7.fhir.convertors.conv30_40.PaymentNotice30_40; -import org.hl7.fhir.convertors.conv30_40.Person30_40; -import org.hl7.fhir.convertors.conv30_40.PlanDefinition30_40; -import org.hl7.fhir.convertors.conv30_40.Practitioner30_40; -import org.hl7.fhir.convertors.conv30_40.PractitionerRole30_40; -import org.hl7.fhir.convertors.conv30_40.Procedure30_40; -import org.hl7.fhir.convertors.conv30_40.ProcedureRequest30_40; -import org.hl7.fhir.convertors.conv30_40.Provenance30_40; -import org.hl7.fhir.convertors.conv30_40.Questionnaire30_40; -import org.hl7.fhir.convertors.conv30_40.QuestionnaireResponse30_40; -import org.hl7.fhir.convertors.conv30_40.RelatedPerson30_40; -import org.hl7.fhir.convertors.conv30_40.RiskAssessment30_40; -import org.hl7.fhir.convertors.conv30_40.Schedule30_40; -import org.hl7.fhir.convertors.conv30_40.SearchParameter30_40; -import org.hl7.fhir.convertors.conv30_40.Sequence30_40; -import org.hl7.fhir.convertors.conv30_40.Slot30_40; -import org.hl7.fhir.convertors.conv30_40.Specimen30_40; -import org.hl7.fhir.convertors.conv30_40.StructureDefinition30_40; -import org.hl7.fhir.convertors.conv30_40.StructureMap30_40; -import org.hl7.fhir.convertors.conv30_40.Subscription30_40; -import org.hl7.fhir.convertors.conv30_40.Substance30_40; -import org.hl7.fhir.convertors.conv30_40.SupplyDelivery30_40; -import org.hl7.fhir.convertors.conv30_40.TestReport30_40; -import org.hl7.fhir.convertors.conv30_40.TestScript30_40; -import org.hl7.fhir.convertors.conv30_40.ValueSet30_40; +import org.hl7.fhir.convertors.conv30_40.*; import org.hl7.fhir.dstu3.model.Parameters; import org.hl7.fhir.dstu3.model.Parameters.ParametersParameterComponent; import org.hl7.fhir.exceptions.FHIRException; @@ -5164,6 +5081,8 @@ public class VersionConvertor_30_40 { return Coverage30_40.convertCoverage((org.hl7.fhir.r4.model.Coverage) src); if (src instanceof org.hl7.fhir.r4.model.DetectedIssue) return DetectedIssue30_40.convertDetectedIssue((org.hl7.fhir.r4.model.DetectedIssue) src); + if (src instanceof org.hl7.fhir.r4.model.Device) + return Device30_40.convertDevice((org.hl7.fhir.r4.model.Device) src); if (src instanceof org.hl7.fhir.r4.model.DeviceUseStatement) return DeviceUseStatement30_40.convertDeviceUseStatement((org.hl7.fhir.r4.model.DeviceUseStatement) src); if (src instanceof org.hl7.fhir.r4.model.DiagnosticReport) diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv30_40/Device30_40.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv30_40/Device30_40.java new file mode 100644 index 000000000..4e77bec9b --- /dev/null +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv30_40/Device30_40.java @@ -0,0 +1,258 @@ +package org.hl7.fhir.convertors.conv30_40; + + +import org.hl7.fhir.convertors.VersionConvertor_30_40; +import org.hl7.fhir.dstu3.model.Device; +import org.hl7.fhir.exceptions.FHIRException; +import org.hl7.fhir.r4.model.Patient; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +/* + Copyright (c) 2011+, HL7, Inc. + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of HL7 nor the names of its contributors may be used to + endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +*/ +// Generated on Sun, Feb 24, 2019 11:37+1100 for FHIR v4.0.0 +public class Device30_40 extends VersionConvertor_30_40 { + + public static org.hl7.fhir.r4.model.Device convertDevice(org.hl7.fhir.dstu3.model.Device src) throws FHIRException { + if (src == null) + return null; + org.hl7.fhir.r4.model.Device tgt = new org.hl7.fhir.r4.model.Device(); + copyDomainResource(src, tgt); + for (org.hl7.fhir.dstu3.model.Identifier t : src.getIdentifier()) tgt.addIdentifier(convertIdentifier(t)); + if (src.hasUdi()) { + org.hl7.fhir.r4.model.Device.DeviceUdiCarrierComponent carrierComponent = tgt.getUdiCarrierFirstRep(); + carrierComponent.setDeviceIdentifierElement(VersionConvertor_30_40.convertString(src.getUdi().getDeviceIdentifierElement())); + carrierComponent.setJurisdictionElement(VersionConvertor_30_40.convertUri(src.getUdi().getJurisdictionElement())); + carrierComponent.setCarrierHRFElement(VersionConvertor_30_40.convertString(src.getUdi().getCarrierHRFElement())); + carrierComponent.setCarrierAIDCElement(VersionConvertor_30_40.convertBase64Binary(src.getUdi().getCarrierAIDCElement())); + carrierComponent.setIssuerElement(VersionConvertor_30_40.convertUri(src.getUdi().getIssuerElement())); + carrierComponent.setEntryTypeElement(convertUDIEntryType(src.getUdi().getEntryTypeElement())); + tgt.setUdiCarrier(Collections.singletonList(carrierComponent)); + org.hl7.fhir.r4.model.Device.DeviceDeviceNameComponent nameComponent = tgt.getDeviceNameFirstRep(); + nameComponent.setNameElement(VersionConvertor_30_40.convertString(src.getUdi().getNameElement())); + nameComponent.setType(org.hl7.fhir.r4.model.Device.DeviceNameType.UDILABELNAME); + } + if (src.hasStatus()) + tgt.setStatusElement(convertFHIRDeviceStatus(src.getStatusElement())); + if (src.hasType()) + tgt.setType(convertCodeableConcept(src.getType())); + if (src.hasLotNumber()) + tgt.setLotNumberElement(convertString(src.getLotNumberElement())); + if (src.hasManufacturer()) + tgt.setManufacturerElement(convertString(src.getManufacturerElement())); + if (src.hasManufactureDate()) + tgt.setManufactureDateElement(convertDateTime(src.getManufactureDateElement())); + if (src.hasExpirationDate()) + tgt.setExpirationDateElement(convertDateTime(src.getExpirationDateElement())); + if (src.hasModelElement()) + tgt.setModelNumberElement(VersionConvertor_30_40.convertString(src.getModelElement())); + if (src.hasVersionElement()) + tgt.setVersion(Collections.singletonList(tgt.getVersionFirstRep().setValueElement(VersionConvertor_30_40.convertString(src.getVersionElement())))); + if (src.hasPatient()) + tgt.setPatient(convertReference(src.getPatient())); + if (src.hasOwner()) + tgt.setOwner(convertReference(src.getOwner())); + if (src.hasContact()) + tgt.setContact(src.getContact().stream().map(VersionConvertor_30_40::convertContactPoint).collect(Collectors.toList())); + if (src.hasLocation()) + tgt.setLocation(convertReference(src.getLocation())); + if (src.hasUrl()) + tgt.setUrlElement(convertUri(src.getUrlElement())); + for (org.hl7.fhir.dstu3.model.Annotation t : src.getNote()) tgt.addNote(convertAnnotation(t)); + for (org.hl7.fhir.dstu3.model.CodeableConcept t : src.getSafety()) tgt.addSafety(convertCodeableConcept(t)); + return tgt; + } + + public static org.hl7.fhir.dstu3.model.Device convertDevice(org.hl7.fhir.r4.model.Device src) throws FHIRException { + if (src == null) + return null; + org.hl7.fhir.dstu3.model.Device tgt = new org.hl7.fhir.dstu3.model.Device(); + copyDomainResource(src, tgt); + for (org.hl7.fhir.r4.model.Identifier t : src.getIdentifier()) tgt.addIdentifier(convertIdentifier(t)); + if (src.hasUdiCarrier()) { + Device.DeviceUdiComponent udi = tgt.getUdi(); + udi.setDeviceIdentifierElement(VersionConvertor_30_40.convertString(src.getUdiCarrierFirstRep().getDeviceIdentifierElement())); + udi.setJurisdictionElement(VersionConvertor_30_40.convertUri(src.getUdiCarrierFirstRep().getJurisdictionElement())); + udi.setCarrierHRFElement(VersionConvertor_30_40.convertString(src.getUdiCarrierFirstRep().getCarrierHRFElement())); + udi.setCarrierAIDCElement(VersionConvertor_30_40.convertBase64Binary(src.getUdiCarrierFirstRep().getCarrierAIDCElement())); + udi.setIssuerElement(VersionConvertor_30_40.convertUri(src.getUdiCarrierFirstRep().getIssuerElement())); + udi.setEntryTypeElement(convertUDIEntryType(src.getUdiCarrierFirstRep().getEntryTypeElement())); + tgt.setUdi(udi); + } + if (src.hasStatus()) + tgt.setStatusElement(convertFHIRDeviceStatus(src.getStatusElement())); + if (src.hasType()) + tgt.setType(convertCodeableConcept(src.getType())); + if (src.hasLotNumber()) + tgt.setLotNumberElement(convertString(src.getLotNumberElement())); + if (src.hasManufacturer()) + tgt.setManufacturerElement(convertString(src.getManufacturerElement())); + if (src.hasManufactureDate()) + tgt.setManufactureDateElement(convertDateTime(src.getManufactureDateElement())); + if (src.hasExpirationDate()) + tgt.setExpirationDateElement(convertDateTime(src.getExpirationDateElement())); + if (src.hasModelNumber()) + tgt.setModel(src.getModelNumber()); + if (src.hasVersion()) + tgt.setVersionElement(VersionConvertor_30_40.convertString(src.getVersion().get(0).getValueElement())); + if (src.hasDeviceName()) + tgt.setUdi(tgt.getUdi().setName(src.getDeviceName().get(0).getName())); + if (src.hasPatient()) + tgt.setPatient(convertReference(src.getPatient())); + if (src.hasOwner()) + tgt.setOwner(convertReference(src.getOwner())); + if (src.hasContact()) + tgt.setContact(src.getContact().stream().map(VersionConvertor_30_40::convertContactPoint).collect(Collectors.toList())); + if (src.hasLocation()) + tgt.setLocation(convertReference(src.getLocation())); + for (org.hl7.fhir.r4.model.ContactPoint t : src.getContact()) tgt.addContact(convertContactPoint(t)); + if (src.hasLocation()) + tgt.setLocation(VersionConvertor_30_40.convertReference(src.getLocation())); + if (src.hasUrl()) + tgt.setUrlElement(convertUri(src.getUrlElement())); + for (org.hl7.fhir.r4.model.Annotation t : src.getNote()) tgt.addNote(convertAnnotation(t)); + for (org.hl7.fhir.r4.model.CodeableConcept t : src.getSafety()) tgt.addSafety(convertCodeableConcept(t)); + return tgt; + } + + static public org.hl7.fhir.r4.model.Enumeration convertFHIRDeviceStatus(org.hl7.fhir.dstu3.model.Enumeration src) throws FHIRException { + if (src == null || src.isEmpty()) + return null; + org.hl7.fhir.r4.model.Enumeration tgt = new org.hl7.fhir.r4.model.Enumeration<>(new org.hl7.fhir.r4.model.Device.FHIRDeviceStatusEnumFactory()); + VersionConvertor_30_40.copyElement(src, tgt); + switch (src.getValue()) { + case ACTIVE: + tgt.setValue(org.hl7.fhir.r4.model.Device.FHIRDeviceStatus.ACTIVE); + break; + case INACTIVE: + tgt.setValue(org.hl7.fhir.r4.model.Device.FHIRDeviceStatus.INACTIVE); + break; + case ENTEREDINERROR: + tgt.setValue(org.hl7.fhir.r4.model.Device.FHIRDeviceStatus.ENTEREDINERROR); + break; + case UNKNOWN: + tgt.setValue(org.hl7.fhir.r4.model.Device.FHIRDeviceStatus.UNKNOWN); + break; + default: + tgt.setValue(org.hl7.fhir.r4.model.Device.FHIRDeviceStatus.NULL); + break; + } + return tgt; + } + + static public org.hl7.fhir.dstu3.model.Enumeration convertFHIRDeviceStatus(org.hl7.fhir.r4.model.Enumeration src) throws FHIRException { + if (src == null || src.isEmpty()) + return null; + org.hl7.fhir.dstu3.model.Enumeration tgt = new org.hl7.fhir.dstu3.model.Enumeration<>(new org.hl7.fhir.dstu3.model.Device.FHIRDeviceStatusEnumFactory()); + VersionConvertor_30_40.copyElement(src, tgt); + switch (src.getValue()) { + case ACTIVE: + tgt.setValue(org.hl7.fhir.dstu3.model.Device.FHIRDeviceStatus.ACTIVE); + break; + case INACTIVE: + tgt.setValue(org.hl7.fhir.dstu3.model.Device.FHIRDeviceStatus.INACTIVE); + break; + case ENTEREDINERROR: + tgt.setValue(org.hl7.fhir.dstu3.model.Device.FHIRDeviceStatus.ENTEREDINERROR); + break; + case UNKNOWN: + tgt.setValue(org.hl7.fhir.dstu3.model.Device.FHIRDeviceStatus.UNKNOWN); + break; + default: + tgt.setValue(org.hl7.fhir.dstu3.model.Device.FHIRDeviceStatus.NULL); + break; + } + return tgt; + } + + static public org.hl7.fhir.r4.model.Enumeration convertUDIEntryType(org.hl7.fhir.dstu3.model.Enumeration src) throws FHIRException { + if (src == null || src.isEmpty()) + return null; + org.hl7.fhir.r4.model.Enumeration tgt = new org.hl7.fhir.r4.model.Enumeration<>(new org.hl7.fhir.r4.model.Device.UDIEntryTypeEnumFactory()); + VersionConvertor_30_40.copyElement(src, tgt); + switch (src.getValue()) { + case BARCODE: + tgt.setValue(org.hl7.fhir.r4.model.Device.UDIEntryType.BARCODE); + break; + case RFID: + tgt.setValue(org.hl7.fhir.r4.model.Device.UDIEntryType.RFID); + break; + case MANUAL: + tgt.setValue(org.hl7.fhir.r4.model.Device.UDIEntryType.MANUAL); + break; + case CARD: + tgt.setValue(org.hl7.fhir.r4.model.Device.UDIEntryType.CARD); + break; + case SELFREPORTED: + tgt.setValue(org.hl7.fhir.r4.model.Device.UDIEntryType.SELFREPORTED); + break; + case UNKNOWN: + tgt.setValue(org.hl7.fhir.r4.model.Device.UDIEntryType.UNKNOWN); + break; + default: + tgt.setValue(org.hl7.fhir.r4.model.Device.UDIEntryType.NULL); + break; + } + return tgt; + } + + static public org.hl7.fhir.dstu3.model.Enumeration convertUDIEntryType(org.hl7.fhir.r4.model.Enumeration src) throws FHIRException { + if (src == null || src.isEmpty()) + return null; + org.hl7.fhir.dstu3.model.Enumeration tgt = new org.hl7.fhir.dstu3.model.Enumeration<>(new org.hl7.fhir.dstu3.model.Device.UDIEntryTypeEnumFactory()); + VersionConvertor_30_40.copyElement(src, tgt); + switch (src.getValue()) { + case BARCODE: + tgt.setValue(org.hl7.fhir.dstu3.model.Device.UDIEntryType.BARCODE); + break; + case RFID: + tgt.setValue(org.hl7.fhir.dstu3.model.Device.UDIEntryType.RFID); + break; + case MANUAL: + tgt.setValue(org.hl7.fhir.dstu3.model.Device.UDIEntryType.MANUAL); + break; + case CARD: + tgt.setValue(org.hl7.fhir.dstu3.model.Device.UDIEntryType.CARD); + break; + case SELFREPORTED: + tgt.setValue(org.hl7.fhir.dstu3.model.Device.UDIEntryType.SELFREPORTED); + break; + case UNKNOWN: + tgt.setValue(org.hl7.fhir.dstu3.model.Device.UDIEntryType.UNKNOWN); + break; + default: + tgt.setValue(org.hl7.fhir.dstu3.model.Device.UDIEntryType.NULL); + break; + } + return tgt; + } +} \ No newline at end of file diff --git a/org.hl7.fhir.convertors/src/test/java/org/hl7/fhir/convertors/conv30_40/Device30_40Test.java b/org.hl7.fhir.convertors/src/test/java/org/hl7/fhir/convertors/conv30_40/Device30_40Test.java new file mode 100644 index 000000000..aa617a1e9 --- /dev/null +++ b/org.hl7.fhir.convertors/src/test/java/org/hl7/fhir/convertors/conv30_40/Device30_40Test.java @@ -0,0 +1,43 @@ +package org.hl7.fhir.convertors.conv30_40; + +import org.hl7.fhir.convertors.VersionConvertor_30_40; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.io.InputStream; + +public class Device30_40Test { + @Test + @DisplayName("Test r4 -> dstu3 device conversion.") + public void test1() throws IOException { + InputStream r4_input = this.getClass().getResourceAsStream("/0_device_40.json"); + InputStream dstu3_expected_output = this.getClass().getResourceAsStream("/0_device_30.json"); + + org.hl7.fhir.r4.model.Device r4_actual = (org.hl7.fhir.r4.model.Device) new org.hl7.fhir.r4.formats.JsonParser().parse(r4_input); + org.hl7.fhir.dstu3.model.Resource dstu3_conv = VersionConvertor_30_40.convertResource(r4_actual, true); + + org.hl7.fhir.dstu3.formats.JsonParser dstu3_parser = new org.hl7.fhir.dstu3.formats.JsonParser(); + org.hl7.fhir.dstu3.model.Resource dstu3_expected = dstu3_parser.parse(dstu3_expected_output); + + Assertions.assertTrue(dstu3_expected.equalsDeep(dstu3_conv), + "Failed comparing\n" + dstu3_parser.composeString(dstu3_expected) + "\nand\n" + dstu3_parser.composeString(dstu3_conv)); + } + + @Test + @DisplayName("Test r4 -> dstu3 device conversion, part 2.") + public void test2() throws IOException { + InputStream r4_input = this.getClass().getResourceAsStream("/1_device_40.json"); + InputStream dstu3_expected_output = this.getClass().getResourceAsStream("/1_device_30.json"); + + org.hl7.fhir.r4.model.Device r4_actual = (org.hl7.fhir.r4.model.Device) new org.hl7.fhir.r4.formats.JsonParser().parse(r4_input); + org.hl7.fhir.dstu3.model.Resource dstu3_conv = VersionConvertor_30_40.convertResource(r4_actual, true); + + org.hl7.fhir.dstu3.formats.JsonParser dstu3_parser = new org.hl7.fhir.dstu3.formats.JsonParser(); + org.hl7.fhir.dstu3.model.Resource dstu3_expected = dstu3_parser.parse(dstu3_expected_output); + + Assertions.assertTrue(dstu3_expected.equalsDeep(dstu3_conv), + "Failed comparing\n" + dstu3_parser.composeString(dstu3_expected) + "\nand\n" + dstu3_parser.composeString(dstu3_expected)); + } +} \ No newline at end of file diff --git a/org.hl7.fhir.convertors/src/test/resources/0_device_30.json b/org.hl7.fhir.convertors/src/test/resources/0_device_30.json new file mode 100644 index 000000000..95555f10d --- /dev/null +++ b/org.hl7.fhir.convertors/src/test/resources/0_device_30.json @@ -0,0 +1,13 @@ +{ + "resourceType": "Device", + "id": "DEV000000000872", + "identifier": [ + { + "system": "https://fresenius.org/device", + "value": "DEV000000000872" + } + ], + "udi": { + "name": "LC021691" + } +} diff --git a/org.hl7.fhir.convertors/src/test/resources/0_device_40.json b/org.hl7.fhir.convertors/src/test/resources/0_device_40.json new file mode 100644 index 000000000..6d3895d27 --- /dev/null +++ b/org.hl7.fhir.convertors/src/test/resources/0_device_40.json @@ -0,0 +1,20 @@ +{ + "resourceType": "Device", + "id": "DEV000000000872", + "identifier": [ + { + "system": "https://fresenius.org/device", + "value": "DEV000000000872" + } + ], + "definition": { + "reference": "Dialysis" + }, + "serialNumber": "LC021691", + "deviceName": [ + { + "name": "LC021691", + "type": "manufacturer-name" + } + ] +} \ No newline at end of file diff --git a/org.hl7.fhir.convertors/src/test/resources/1_device_30.json b/org.hl7.fhir.convertors/src/test/resources/1_device_30.json new file mode 100644 index 000000000..e06402f5a --- /dev/null +++ b/org.hl7.fhir.convertors/src/test/resources/1_device_30.json @@ -0,0 +1,13 @@ +{ + "resourceType": "Device", + "id": "DEV000000000873", + "identifier": [ + { + "system": "https://fresenius.org/device", + "value": "DEV000000000873" + } + ], + "udi": { + "name": "LC020678" + } +} \ No newline at end of file diff --git a/org.hl7.fhir.convertors/src/test/resources/1_device_40.json b/org.hl7.fhir.convertors/src/test/resources/1_device_40.json new file mode 100644 index 000000000..d7bef3a9b --- /dev/null +++ b/org.hl7.fhir.convertors/src/test/resources/1_device_40.json @@ -0,0 +1,20 @@ +{ + "resourceType": "Device", + "id": "DEV000000000873", + "identifier": [ + { + "system": "https://fresenius.org/device", + "value": "DEV000000000873" + } + ], + "definition": { + "reference": "Dialysis" + }, + "serialNumber": "LC020678", + "deviceName": [ + { + "name": "LC020678", + "type": "manufacturer-name" + } + ] +} \ No newline at end of file From c2fb9e8fd3d2cebbeb9ff623d5dd1e2f525ee3c4 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Fri, 25 Sep 2020 03:25:09 +1000 Subject: [PATCH 36/73] Add rendering for must support on types, profiles, targets --- .../fhir/r5/conformance/ProfileUtilities.java | 80 ++++++++++++++++--- .../hl7/fhir/r5/utils/ToolingExtensions.java | 3 + 2 files changed, 72 insertions(+), 11 deletions(-) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfileUtilities.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfileUtilities.java index 532fef47d..fbb99dd77 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfileUtilities.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfileUtilities.java @@ -3245,14 +3245,22 @@ public class ProfileUtilities extends TranslatingUtilities { tl = t; if (t.hasTarget()) { c.getPieces().add(gen.new Piece(corePath+"references.html", t.getWorkingCode(), null)); + if (isMustSupportDirect(t) && e.getMustSupport()) { + c.addPiece(gen.new Piece(null, " ", null)); + c.addStyledText(translate("sd.table", "This type must be supported"), "S", "white", "red", null, false); + } c.getPieces().add(gen.new Piece(null, "(", null)); boolean tfirst = true; - for (UriType u : t.getTargetProfile()) { + for (CanonicalType u : t.getTargetProfile()) { if (tfirst) tfirst = false; else c.addPiece(gen.new Piece(null, " | ", null)); genTargetLink(gen, profileBaseFileName, corePath, c, t, u.getValue()); + if (isMustSupport(u) && e.getMustSupport()) { + c.addPiece(gen.new Piece(null, " ", null)); + c.addStyledText(translate("sd.table", "This target must be supported"), "S", "white", "red", null, false); + } } c.getPieces().add(gen.new Piece(null, ")", null)); if (t.getAggregation().size() > 0) { @@ -3289,6 +3297,10 @@ public class ProfileUtilities extends TranslatingUtilities { } } else c.addPiece(checkForNoChange(t, gen.new Piece((p.getValue().startsWith(corePath)? corePath: "")+ref, t.getWorkingCode(), null))); + if (isMustSupport(p) && e.getMustSupport()) { + c.addPiece(gen.new Piece(null, " ", null)); + c.addStyledText(translate("sd.table", "This profile must be supported"), "S", "white", "red", null, false); + } } } else { String tc = t.getWorkingCode(); @@ -3301,8 +3313,13 @@ public class ProfileUtilities extends TranslatingUtilities { } } else if (pkp != null && pkp.hasLinkFor(tc)) { c.addPiece(checkForNoChange(t, gen.new Piece(pkp.getLinkFor(corePath, tc), tc, null))); - } else + } else { c.addPiece(checkForNoChange(t, gen.new Piece(null, tc, null))); + } + if (isMustSupportDirect(t) && e.getMustSupport()) { + c.addPiece(gen.new Piece(null, " ", null)); + c.addStyledText(translate("sd.table", "This type must be supported"), "S", "white", "red", null, false); + } } } return c; @@ -3931,6 +3948,10 @@ public class ProfileUtilities extends TranslatingUtilities { c.getPieces().add(gen.new Piece(corePath+"datatypes.html#canonical", "canonical", null)); else c.getPieces().add(gen.new Piece(corePath+"references.html#Reference", "Reference", null)); + if (isMustSupportDirect(tr) && element.getMustSupport()) { + c.addPiece(gen.new Piece(null, " ", null)); + c.addStyledText(translate("sd.table", "This type must be supported"), "S", "white", "red", null, false); + } c.getPieces().add(gen.new Piece(null, "(", null)); } boolean first = true; @@ -3938,6 +3959,10 @@ public class ProfileUtilities extends TranslatingUtilities { if (!first) c.getPieces().add(gen.new Piece(null, " | ", null)); genTargetLink(gen, profileBaseFileName, corePath, c, tr, rt.getValue()); + if (isMustSupport(rt) && element.getMustSupport()) { + c.addPiece(gen.new Piece(null, " ", null)); + c.addStyledText(translate("sd.table", "This target must be supported"), "S", "white", "red", null, false); + } first = false; } if (first) @@ -3956,20 +3981,23 @@ public class ProfileUtilities extends TranslatingUtilities { choicerow.getCells().add(gen.new Cell()); choicerow.getCells().add(gen.new Cell(null, null, "", null, null)); choicerow.setIcon("icon_primitive.png", HierarchicalTableGenerator.TEXT_ICON_PRIMITIVE); - choicerow.getCells().add(gen.new Cell(null, corePath+"datatypes.html#"+t, sd.getType(), null, null)); - // } else if (definitions.getConstraints().contthnsKey(t)) { - // ProfiledType pt = definitions.getConstraints().get(t); - // choicerow.getCells().add(gen.new Cell(null, null, e.getName().replace("[x]", Utilities.capitalize(pt.getBaseType())), definitions.getTypes().containsKey(t) ? definitions.getTypes().get(t).getDefinition() : null, null)); - // choicerow.getCells().add(gen.new Cell()); - // choicerow.getCells().add(gen.new Cell(null, null, "", null, null)); - // choicerow.setIcon("icon_datatype.gif", HierarchicalTableGenerator.TEXT_ICON_DATATYPE); - // choicerow.getCells().add(gen.new Cell(null, definitions.getSrcFile(t)+".html#"+t.replace("*", "open"), t, null, null)); + Cell c = gen.new Cell(null, corePath+"datatypes.html#"+t, sd.getType(), null, null); + choicerow.getCells().add(c); + if (isMustSupport(tr) && element.getMustSupport()) { + c.addPiece(gen.new Piece(null, " ", null)); + c.addStyledText(translate("sd.table", "This type must be supported"), "S", "white", "red", null, false); + } } else { choicerow.getCells().add(gen.new Cell(null, null, tail(element.getPath()).replace("[x]", Utilities.capitalize(t)), sd.getDescription(), null)); choicerow.getCells().add(gen.new Cell()); choicerow.getCells().add(gen.new Cell(null, null, "", null, null)); choicerow.setIcon("icon_datatype.gif", HierarchicalTableGenerator.TEXT_ICON_DATATYPE); - choicerow.getCells().add(gen.new Cell(null, pkp.getLinkFor(corePath, t), sd.getType(), null, null)); + Cell c = gen.new Cell(null, pkp.getLinkFor(corePath, t), sd.getType(), null, null); + choicerow.getCells().add(c); + if (isMustSupport(tr) && element.getMustSupport()) { + c.addPiece(gen.new Piece(null, " ", null)); + c.addStyledText(translate("sd.table", "This type must be supported"), "S", "white", "red", null, false); + } } if (tr.hasProfile()) { Cell typeCell = choicerow.getCells().get(3); @@ -3982,6 +4010,10 @@ public class ProfileUtilities extends TranslatingUtilities { typeCell.addPiece(gen.new Piece(null, "?gen-e2?", null)); else typeCell.addPiece(gen.new Piece(psd.getUserString("path"), psd.getName(), psd.present())); + if (isMustSupport(pt) && element.getMustSupport()) { + typeCell.addPiece(gen.new Piece(null, " ", null)); + typeCell.addStyledText(translate("sd.table", "This profile must be supported"), "S", "white", "red", null, false); + } } typeCell.addPiece(gen.new Piece(null, ")", null)); @@ -6177,6 +6209,32 @@ public class ProfileUtilities extends TranslatingUtilities { return grp; } + public static boolean isMustSupportDirect(TypeRefComponent tr) { + return ("true".equals(ToolingExtensions.readStringExtension(tr, ToolingExtensions.EXT_MUST_SUPPORT))); + } + public static boolean isMustSupport(TypeRefComponent tr) { + if ("true".equals(ToolingExtensions.readStringExtension(tr, ToolingExtensions.EXT_MUST_SUPPORT))) { + return true; + } + if (isMustSupport(tr.getProfile())) { + return true; + } + return isMustSupport(tr.getTargetProfile()); + } + + public static boolean isMustSupport(List profiles) { + for (CanonicalType ct : profiles) { + if (isMustSupport(ct)) { + return true; + } + } + return false; + } + + + public static boolean isMustSupport(CanonicalType profile) { + return "true".equals(ToolingExtensions.readStringExtension(profile, ToolingExtensions.EXT_MUST_SUPPORT)); + } } \ No newline at end of file diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/ToolingExtensions.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/ToolingExtensions.java index 40f5f73f6..175fec654 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/ToolingExtensions.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/ToolingExtensions.java @@ -180,6 +180,7 @@ public class ToolingExtensions { public static final String EXT_OLD_CONCEPTMAP_EQUIVALENCE = "http://hl7.org/fhir/1.0/StructureDefinition/extension-ConceptMap.element.target.equivalence"; public static final String EXT_EXP_FRAGMENT = "http://hl7.org/fhir/tools/StructureDefinition/expansion-codesystem-fragment"; public static final String EXT_EXP_TOOCOSTLY = "http://hl7.org/fhir/StructureDefinition/valueset-toocostly"; + public static final String EXT_MUST_SUPPORT = "http://hl7.org/fhir/StructureDefinition/elementdefinition-type-must-support"; // specific extension helpers @@ -335,6 +336,8 @@ public class ToolingExtensions { return ((DecimalType) ex.getValue()).asStringValue(); if ((ex.getValue() instanceof MarkdownType)) return ((MarkdownType) ex.getValue()).getValue(); + if ((ex.getValue() instanceof PrimitiveType)) + return ((PrimitiveType) ex.getValue()).primitiveValue(); if (!(ex.getValue() instanceof StringType)) return null; return ((StringType) ex.getValue()).getValue(); From 73d5a845bffa79fb58ea56fdbff28310b21ad3cf Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Fri, 25 Sep 2020 03:25:59 +1000 Subject: [PATCH 37/73] Add new validation for must-support on types / profiles / targets + improve extension validation --- .../fhir/utilities/i18n/I18nConstants.java | 2 + .../src/main/resources/Messages.properties | 5 +- .../hl7/fhir/validation/BaseValidator.java | 5 +- .../instance/InstanceValidator.java | 8 ++- .../instance/SpecialExtensions.java | 39 +++++++++++ .../type/StructureDefinitionValidator.java | 64 +++++++++++++++++++ 6 files changed, 118 insertions(+), 5 deletions(-) create mode 100644 org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/SpecialExtensions.java 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 1d5359d76..4d9da697d 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 @@ -341,6 +341,8 @@ public class I18nConstants { public static final String RESOURCE_TYPE_MISMATCH_FOR___ = "Resource_type_mismatch_for___"; public static final String SAME_ID_ON_MULTIPLE_ELEMENTS__IN_ = "Same_id_on_multiple_elements__in_"; public static final String SD_MUST_HAVE_DERIVATION = "SD_MUST_HAVE_DERIVATION"; + public static final String SD_NESTED_MUST_SUPPORT_DIFF = "SD_NESTED_MUST_SUPPORT_DIFF"; + public static final String SD_NESTED_MUST_SUPPORT_SNAPSHOT = "SD_NESTED_MUST_SUPPORT_SNAPSHOT"; public static final String SEARCHPARAMETER_BASE_WRONG = "SEARCHPARAMETER_BASE_WRONG"; public static final String SEARCHPARAMETER_EXP_WRONG = "SEARCHPARAMETER_EXP_WRONG"; public static final String SEARCHPARAMETER_NOTFOUND = "SEARCHPARAMETER_NOTFOUND"; diff --git a/org.hl7.fhir.utilities/src/main/resources/Messages.properties b/org.hl7.fhir.utilities/src/main/resources/Messages.properties index 562e34887..18bee95a6 100644 --- a/org.hl7.fhir.utilities/src/main/resources/Messages.properties +++ b/org.hl7.fhir.utilities/src/main/resources/Messages.properties @@ -608,4 +608,7 @@ REFERENCE_REF_SUSPICIOUS = The syntax of the reference ''{0}'' looks incorrect, TYPE_SPECIFIC_CHECKS_DT_QTY_NO_ANNOTATIONS = UCUM Codes that contain human readable annotations like {0} can be misleading. Best Practice is not to use annotations in the UCUM code, and rather to make sure that Quantity.unit is correctly human readable XHTML_XHTML_ELEMENT_ILLEGAL_IN_PARA = Illegal element name inside in a paragraph in the XHTML (''{0}'') UNSUPPORTED_IDENTIFIER_PATTERN_PROPERTY_NOT_SUPPORTED_FOR_DISCRIMINATOR_FOR_SLICE = Unsupported property {3} on type {2} for pattern for discriminator({0}) for slice {1} -UNSUPPORTED_IDENTIFIER_PATTERN_NO_PROPERTY_NOT_SUPPORTED_FOR_DISCRIMINATOR_FOR_SLICE = Unsupported: no properties with values found on type {2} for pattern for discriminator({0}) for slice {1} \ No newline at end of file +UNSUPPORTED_IDENTIFIER_PATTERN_NO_PROPERTY_NOT_SUPPORTED_FOR_DISCRIMINATOR_FOR_SLICE = Unsupported: no properties with values found on type {2} for pattern for discriminator({0}) for slice {1} +SD_NESTED_MUST_SUPPORT_DIFF = The element {0} has types/profiles/targets that are marked as must support, but the element itself is not marked as must-support. The inner must-supports will be ignored unless the element inherits must-support = true +SD_NESTED_MUST_SUPPORT_SNAPSHOT = The element {0} has types/profiles/targets that are marked as must support, but the element itself is not marked as must-support + \ No newline at end of file diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/BaseValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/BaseValidator.java index 9e1bd5dd3..c36db51d3 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/BaseValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/BaseValidator.java @@ -296,9 +296,10 @@ public class BaseValidator { * Set this parameter to false if the validation does not pass * @return Returns thePass (in other words, returns true if the rule did not fail validation) */ - protected boolean hint(List errors, IssueType type, String path, boolean thePass, String msg) { + protected boolean hint(List errors, IssueType type, String path, boolean thePass, String theMessage, Object... theMessageArguments) { if (!thePass) { - addValidationMessage(errors, type, -1, -1, path, msg, IssueSeverity.INFORMATION, null); + String message = context.formatMessage(theMessage, theMessageArguments); + addValidationMessage(errors, type, -1, -1, path, message, IssueSeverity.INFORMATION, null); } return thePass; } 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 02aee0df3..0c7ab8330 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 @@ -483,7 +483,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat private boolean isKnownExtension(String url) { // Added structuredefinition-expression and following extensions explicitly because they weren't defined in the version of the spec they need to be used with - if ((allowExamples && (url.contains("example.org") || url.contains("acme.com"))) || url.contains("nema.org") || url.startsWith("http://hl7.org/fhir/tools/StructureDefinition/") || url.equals("http://hl7.org/fhir/StructureDefinition/structuredefinition-expression") || url.equals(VersionConvertorConstants.IG_DEPENDSON_PACKAGE_EXTENSION)) + if ((allowExamples && (url.contains("example.org") || url.contains("acme.com"))) || url.contains("nema.org") || url.startsWith("http://hl7.org/fhir/tools/StructureDefinition/") || url.equals("http://hl7.org/fhir/StructureDefinition/structuredefinition-expression")) return true; for (String s : extensionDomains) if (url.startsWith(s)) @@ -1521,6 +1521,8 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (extensionUrl.equals(profile.getUrl())) { rule(errors, IssueType.INVALID, element.line(), element.col(), path + "[url='" + url + "']", hasExtensionSlice(profile, url), I18nConstants.EXTENSION_EXT_SUBEXTENSION_INVALID, url, profile.getUrl()); } + } else if (SpecialExtensions.isKnownExtension(url)) { + ex = SpecialExtensions.getDefinition(url); } else if (rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, allowUnknownExtension(url), I18nConstants.EXTENSION_EXT_UNKNOWN_NOTHERE, url)) { hint(errors, IssueType.STRUCTURE, element.line(), element.col(), path, isKnownExtension(url), I18nConstants.EXTENSION_EXT_UNKNOWN, url); } @@ -1556,6 +1558,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat return ex; } + private boolean hasExtensionSlice(StructureDefinition profile, String sliceName) { for (ElementDefinition ed : profile.getSnapshot().getElement()) { if (ed.getPath().equals("Extension.extension.url") && ed.hasFixed() && sliceName.equals(ed.getFixed().primitiveValue())) { @@ -1933,7 +1936,8 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (fetcher != null) { boolean found; try { - found = isDefinitionURL(url) || (allowExamples && (url.contains("example.org") || url.contains("acme.com")) || url.contains("acme.org")) || (url.startsWith("http://hl7.org/fhir/tools")) || fetcher.resolveURL(appContext, path, url); + found = isDefinitionURL(url) || (allowExamples && (url.contains("example.org") || url.contains("acme.com")) || url.contains("acme.org")) || (url.startsWith("http://hl7.org/fhir/tools")) || fetcher.resolveURL(appContext, path, url) || + SpecialExtensions.isKnownExtension(url); } catch (IOException e1) { found = false; } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/SpecialExtensions.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/SpecialExtensions.java new file mode 100644 index 000000000..a51f75ef1 --- /dev/null +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/SpecialExtensions.java @@ -0,0 +1,39 @@ +package org.hl7.fhir.validation.instance; + +import java.io.IOException; +import java.io.InputStream; + +import org.hl7.fhir.convertors.VersionConvertorConstants; +import org.hl7.fhir.exceptions.FHIRFormatError; +import org.hl7.fhir.r5.formats.JsonParser; +import org.hl7.fhir.r5.formats.XmlParser; +import org.hl7.fhir.r5.model.StructureDefinition; +import org.hl7.fhir.utilities.Utilities; + +public class SpecialExtensions { + + // copied from R5 spec + private static final String MUST_SUPPORT_SOURCE = "{\"resourceType\" : \"StructureDefinition\",\"id\" : \"elementdefinition-type-must-support\",\"extension\" : [{\"url\" : \"http://hl7.org/fhir/StructureDefinition/structuredefinition-wg\",\"valueCode\" : \"fhir\"},{\"url\" : \"http://hl7.org/fhir/StructureDefinition/structuredefinition-fmm\",\"valueInteger\" : 1}],\"url\" : \"http://hl7.org/fhir/StructureDefinition/elementdefinition-type-must-support\",\"version\" : \"4.5.0\",\"name\" : \"type-must-support\",\"status\" : \"draft\",\"date\" : \"2015-02-28\",\"publisher\" : \"Health Level Seven, Inc. - FHIR Core WG\",\"contact\" : [{\"telecom\" : [{\"system\" : \"url\",\"value\" : \"http://hl7.org/special/committees/FHIR\"}]}],\"description\" : \"If true indicates that the specified type, profile or targetProfile must be supported by implementations.\",\"fhirVersion\" : \"4.5.0\",\"mapping\" : [{\"identity\" : \"rim\",\"uri\" : \"http://hl7.org/v3\",\"name\" : \"RIM Mapping\"}],\"kind\" : \"complex-type\",\"abstract\" : false,\"context\" : [{\"type\" : \"element\",\"expression\" : \"ElementDefinition.type\"},{\"type\" : \"element\",\"expression\" : \"ElementDefinition.type.profile\"},{\"type\" : \"element\",\"expression\" : \"ElementDefinition.type.targetProfile\"}],\"type\" : \"Extension\",\"baseDefinition\" : \"http://hl7.org/fhir/StructureDefinition/Extension\",\"derivation\" : \"constraint\",\"snapshot\" : {\"element\" : [{\"id\" : \"Extension\",\"path\" : \"Extension\",\"short\" : \"The specified type/profile/target must be supported by implementations\",\"definition\" : \"If true indicates that the specified type, profile or targetProfile must be supported by implementations.\",\"comment\" : \"An element may be labelled as must support. This extension clarifies which types/profiles/targetProfiles are must-support. It has no meaning if the element itself is not must-support. If the element is labelled must-support, and none of the options are labelled as must support, then an application must support at least one of the possible options, but is not required to support all of them.\",\"min\" : 0,\"max\" : \"1\",\"base\" : {\"path\" : \"Extension\",\"min\" : 0,\"max\" : \"*\"},\"constraint\" : [{\"key\" : \"ele-1\",\"severity\" : \"error\",\"human\" : \"All FHIR elements must have a @value or children\",\"expression\" : \"hasValue() or (children().count() > id.count())\",\"xpath\" : \"@value|f:*|h:div\",\"source\" : \"http://hl7.org/fhir/StructureDefinition/Element\"},{\"key\" : \"ext-1\",\"severity\" : \"error\",\"human\" : \"Must have either extensions or value[x], not both\",\"expression\" : \"extension.exists() != value.exists()\",\"xpath\" : \"exists(f:extension)!=exists(f:*[starts-with(local-name(.), 'value')])\",\"source\" : \"http://hl7.org/fhir/StructureDefinition/Extension\"}],\"isModifier\" : false},{\"id\" : \"Extension.id\",\"path\" : \"Extension.id\",\"representation\" : [\"xmlAttr\"],\"short\" : \"Unique id for inter-element referencing\",\"definition\" : \"Unique id for the element within a resource (for internal references). This may be any string value that does not contain spaces.\",\"min\" : 0,\"max\" : \"1\",\"base\" : {\"path\" : \"Element.id\",\"min\" : 0,\"max\" : \"1\"},\"type\" : [{\"extension\" : [{\"url\" : \"http://hl7.org/fhir/StructureDefinition/structuredefinition-fhir-type\",\"valueUri\" : \"string\"}],\"code\" : \"http://hl7.org/fhirpath/System.String\"}],\"isModifier\" : false,\"isSummary\" : false,\"mapping\" : [{\"identity\" : \"rim\",\"map\" : \"n/a\"}]},{\"id\" : \"Extension.extension\",\"path\" : \"Extension.extension\",\"slicing\" : {\"discriminator\" : [{\"type\" : \"value\",\"path\" : \"url\"}],\"description\" : \"Extensions are always sliced by (at least) url\",\"rules\" : \"open\"},\"short\" : \"Extension\",\"definition\" : \"An Extension\",\"min\" : 0,\"max\" : \"0\",\"base\" : {\"path\" : \"Element.extension\",\"min\" : 0,\"max\" : \"*\"},\"type\" : [{\"code\" : \"Extension\"}],\"constraint\" : [{\"key\" : \"ele-1\",\"severity\" : \"error\",\"human\" : \"All FHIR elements must have a @value or children\",\"expression\" : \"hasValue() or (children().count() > id.count())\",\"xpath\" : \"@value|f:*|h:div\",\"source\" : \"http://hl7.org/fhir/StructureDefinition/Element\"},{\"key\" : \"ext-1\",\"severity\" : \"error\",\"human\" : \"Must have either extensions or value[x], not both\",\"expression\" : \"extension.exists() != value.exists()\",\"xpath\" : \"exists(f:extension)!=exists(f:*[starts-with(local-name(.), \\\"value\\\")])\",\"source\" : \"http://hl7.org/fhir/StructureDefinition/Extension\"}],\"isModifier\" : false,\"isSummary\" : false},{\"id\" : \"Extension.url\",\"path\" : \"Extension.url\",\"representation\" : [\"xmlAttr\"],\"short\" : \"identifies the meaning of the extension\",\"definition\" : \"Source of the definition for the extension code - a logical name or a URL.\",\"comment\" : \"The definition may point directly to a computable or human-readable definition of the extensibility codes, or it may be a logical URI as declared in some other specification. The definition SHALL be a URI for the Structure Definition defining the extension.\",\"min\" : 1,\"max\" : \"1\",\"base\" : {\"path\" : \"Extension.url\",\"min\" : 1,\"max\" : \"1\"},\"type\" : [{\"extension\" : [{\"url\" : \"http://hl7.org/fhir/StructureDefinition/structuredefinition-fhir-type\",\"valueUri\" : \"uri\"}],\"code\" : \"http://hl7.org/fhirpath/System.String\"}],\"fixedUri\" : \"http://hl7.org/fhir/StructureDefinition/elementdefinition-type-must-support\",\"isModifier\" : false,\"isSummary\" : false,\"mapping\" : [{\"identity\" : \"rim\",\"map\" : \"N/A\"}]},{\"id\" : \"Extension.value[x]\",\"path\" : \"Extension.value[x]\",\"short\" : \"Value of extension\",\"definition\" : \"Value of extension - must be one of a constrained set of the data types (see [Extensibility](extensibility.html) for a list).\",\"min\" : 1,\"max\" : \"1\",\"base\" : {\"path\" : \"Extension.value[x]\",\"min\" : 0,\"max\" : \"1\"},\"type\" : [{\"code\" : \"boolean\"}],\"constraint\" : [{\"key\" : \"ele-1\",\"severity\" : \"error\",\"human\" : \"All FHIR elements must have a @value or children\",\"expression\" : \"hasValue() or (children().count() > id.count())\",\"xpath\" : \"@value|f:*|h:div\",\"source\" : \"http://hl7.org/fhir/StructureDefinition/Element\"}],\"isModifier\" : false,\"isSummary\" : false,\"mapping\" : [{\"identity\" : \"rim\",\"map\" : \"N/A\"}]}]},\"differential\" : {\"element\" : [{\"id\" : \"Extension\",\"path\" : \"Extension\",\"short\" : \"The specified type/profile/target must be supported by implementations\",\"definition\" : \"If true indicates that the specified type, profile or targetProfile must be supported by implementations.\",\"comment\" : \"An element may be labelled as must support. This extension clarifies which types/profiles/targetProfiles are must-support. It has no meaning if the element itself is not must-support. If the element is labelled must-support, and none of the options are labelled as must support, then an application must support at least one of the possible options, but is not required to support all of them.\",\"min\" : 0,\"max\" : \"1\"},{\"id\" : \"Extension.extension\",\"path\" : \"Extension.extension\",\"max\" : \"0\"},{\"id\" : \"Extension.url\",\"path\" : \"Extension.url\",\"fixedUri\" : \"http://hl7.org/fhir/StructureDefinition/elementdefinition-type-must-support\"},{\"id\" : \"Extension.value[x]\",\"path\" : \"Extension.value[x]\",\"min\" : 1,\"type\" : [{\"code\" : \"boolean\"}]}]}}"; + + public static boolean isKnownExtension(String url) { + return Utilities.existsInList(url, + "http://hl7.org/fhir/StructureDefinition/elementdefinition-type-must-support" + ); + } + + public static StructureDefinition getDefinition(String url) { + try { + switch (url) { + case "http://hl7.org/fhir/StructureDefinition/elementdefinition-type-must-support" : return makeMustSupport(); + default: return null; + } + } catch (Exception e) { + return null; + } + } + + private static StructureDefinition makeMustSupport() throws FHIRFormatError, IOException { + return (StructureDefinition) new JsonParser().parse(MUST_SUPPORT_SOURCE); + } + +} 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 d7dec41cd..f7631ef8b 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 @@ -28,6 +28,7 @@ import org.hl7.fhir.r5.model.StructureDefinition.TypeDerivationRule; import org.hl7.fhir.r5.model.SearchParameter; import org.hl7.fhir.r5.model.ValueSet; import org.hl7.fhir.r5.utils.FHIRPathEngine; +import org.hl7.fhir.r5.utils.ToolingExtensions; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.VersionUtilities; import org.hl7.fhir.utilities.i18n.I18nConstants; @@ -95,6 +96,69 @@ public class StructureDefinitionValidator extends BaseValidator { } catch (FHIRException | IOException e) { rule(errors, IssueType.EXCEPTION, stack.getLiteralPath(), false, I18nConstants.ERROR_GENERATING_SNAPSHOT, e.getMessage()); } + List differentials = src.getChildrenByName("differential"); + List snapshots = src.getChildrenByName("snapshot"); + for (Element differential : differentials) { + validateElementList(errors, differential, stack.push(differential, -1, null, null), false, snapshots.size() > 0); + } + for (Element snapshot : snapshots) { + validateElementList(errors, snapshot, stack.push(snapshot, -1, null, null), true, true); + } + } + + private void validateElementList(List errors, Element elementList, NodeStack stack, boolean snapshot, boolean hasSnapshot) { + List elements = elementList.getChildrenByName("element"); + int cc = 0; + for (Element element : elements) { + validateElementDefinition(errors, element, stack.push(element, cc, null, null), snapshot, hasSnapshot); + cc++; + } + } + + private void validateElementDefinition(List errors, Element element, NodeStack stack, boolean snapshot, boolean hasSnapshot) { + boolean typeMustSupport = false; + List types = element.getChildrenByName("type"); + for (Element type : types) { + if (hasMustSupportExtension(type)) { + typeMustSupport = true; + } + } + if (typeMustSupport) { + if (snapshot) { + rule(errors, IssueType.EXCEPTION, stack.getLiteralPath(), "true".equals(element.getChildValue("mustSupport")), I18nConstants.SD_NESTED_MUST_SUPPORT_SNAPSHOT, element.getNamedChildValue("path")); + } else { + hint(errors, IssueType.EXCEPTION, stack.getLiteralPath(), hasSnapshot || "true".equals(element.getChildValue("mustSupport")), I18nConstants.SD_NESTED_MUST_SUPPORT_DIFF, element.getNamedChildValue("path")); + } + } + } + + private boolean hasMustSupportExtension(Element type) { + if ("true".equals(getExtensionValue(type, ToolingExtensions.EXT_MUST_SUPPORT))) { + return true; + } + List profiles = type.getChildrenByName("profile"); + for (Element profile : profiles) { + if ("true".equals(getExtensionValue(profile, ToolingExtensions.EXT_MUST_SUPPORT))) { + return true; + } + } + profiles = type.getChildrenByName("targetProfile"); + for (Element profile : profiles) { + if ("true".equals(getExtensionValue(profile, ToolingExtensions.EXT_MUST_SUPPORT))) { + return true; + } + } + return false; + } + + private String getExtensionValue(Element element, String url) { + List extensions = element.getChildrenByName("extension"); + for (Element extension : extensions) { + if (url.equals(extension.getNamedChildValue("url"))) { + return extension.getNamedChildValue("value"); + } + } + return null; } private StructureDefinition loadAsSD(Element src) throws FHIRException, IOException { From dfaefde01a6a1f9dd1b4088d5e82ed95a1e338af Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Fri, 25 Sep 2020 03:26:48 +1000 Subject: [PATCH 38/73] add when rendering turtle to HTML --- .../src/main/java/org/hl7/fhir/utilities/turtle/Turtle.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/turtle/Turtle.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/turtle/Turtle.java index a92f03c66..a555698a3 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/turtle/Turtle.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/turtle/Turtle.java @@ -384,12 +384,12 @@ public class Turtle { public String asHtml() throws Exception { StringBuilder b = new StringBuilder(); - b.append("

\r\n");
+    b.append("
\r\n");
     commitPrefixes(b);
     for (Section s : sections) {
       commitSection(b, s);
     }
-    b.append("
\r\n"); + b.append("
\r\n"); b.append("\r\n"); return b.toString(); } From cf6eb7b10c274d0a6a276f9cae58f39edd0721b0 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Fri, 25 Sep 2020 03:29:54 +1000 Subject: [PATCH 39/73] RELEASE_NOTES.md --- RELEASE_NOTES.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index de602e213..a9cd87f89 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,9 +1,12 @@ Validator: * no changes with impact +* Add new validation for must-support on types / profiles / targets + improve Extension validation Other code changes: * Ensure "I" flag in profile table representation is not used just for infrastructural constraints * Render multiple values for properties in CodeSystems if they exist * Fix for npe rendering resources based on profiles * fix for use of "current" as version -* hack for past bad package URLs \ No newline at end of file +* hack for past bad package URLs +* Add rendering for must support on types, profiles, targets +* add when rendering turtle to HTML \ No newline at end of file From cce35705a6671f9113e27404eb92e8b572f8dded Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Fri, 25 Sep 2020 03:37:46 +1000 Subject: [PATCH 40/73] fix notes --- RELEASE_NOTES.md | 1 - 1 file changed, 1 deletion(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index a9cd87f89..fd314bfee 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,5 +1,4 @@ Validator: -* no changes with impact * Add new validation for must-support on types / profiles / targets + improve Extension validation Other code changes: From b578cfbc0d504de2061cc0bf4313fa6b2257d2b3 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Fri, 25 Sep 2020 04:06:36 +1000 Subject: [PATCH 41/73] Gg v5114 b (#356) * Ensure "I" flag in profile table representation is not used for underlying infrastructural constraints that exist everywhere * render multiple values for properties if they exist * fix for npe * fix for use of "current" as version * fix bad package URLs as they are loaded * RELEASE_NOTES.md * Add rendering for must support on types, profiles, targets * Add new validation for must-support on types / profiles / targets + improve extension validation * add when rendering turtle to HTML * RELEASE_NOTES.md * fix notes --- RELEASE_NOTES.md | 6 +- .../fhir/r5/conformance/ProfileUtilities.java | 80 ++++++++++++++++--- .../hl7/fhir/r5/utils/ToolingExtensions.java | 3 + .../fhir/utilities/i18n/I18nConstants.java | 2 + .../org/hl7/fhir/utilities/turtle/Turtle.java | 4 +- .../src/main/resources/Messages.properties | 5 +- .../hl7/fhir/validation/BaseValidator.java | 5 +- .../instance/InstanceValidator.java | 8 +- .../instance/SpecialExtensions.java | 39 +++++++++ .../type/StructureDefinitionValidator.java | 64 +++++++++++++++ 10 files changed, 196 insertions(+), 20 deletions(-) create mode 100644 org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/SpecialExtensions.java diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index de602e213..fd314bfee 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,9 +1,11 @@ Validator: -* no changes with impact +* Add new validation for must-support on types / profiles / targets + improve Extension validation Other code changes: * Ensure "I" flag in profile table representation is not used just for infrastructural constraints * Render multiple values for properties in CodeSystems if they exist * Fix for npe rendering resources based on profiles * fix for use of "current" as version -* hack for past bad package URLs \ No newline at end of file +* hack for past bad package URLs +* Add rendering for must support on types, profiles, targets +* add when rendering turtle to HTML \ No newline at end of file diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfileUtilities.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfileUtilities.java index 532fef47d..fbb99dd77 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfileUtilities.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfileUtilities.java @@ -3245,14 +3245,22 @@ public class ProfileUtilities extends TranslatingUtilities { tl = t; if (t.hasTarget()) { c.getPieces().add(gen.new Piece(corePath+"references.html", t.getWorkingCode(), null)); + if (isMustSupportDirect(t) && e.getMustSupport()) { + c.addPiece(gen.new Piece(null, " ", null)); + c.addStyledText(translate("sd.table", "This type must be supported"), "S", "white", "red", null, false); + } c.getPieces().add(gen.new Piece(null, "(", null)); boolean tfirst = true; - for (UriType u : t.getTargetProfile()) { + for (CanonicalType u : t.getTargetProfile()) { if (tfirst) tfirst = false; else c.addPiece(gen.new Piece(null, " | ", null)); genTargetLink(gen, profileBaseFileName, corePath, c, t, u.getValue()); + if (isMustSupport(u) && e.getMustSupport()) { + c.addPiece(gen.new Piece(null, " ", null)); + c.addStyledText(translate("sd.table", "This target must be supported"), "S", "white", "red", null, false); + } } c.getPieces().add(gen.new Piece(null, ")", null)); if (t.getAggregation().size() > 0) { @@ -3289,6 +3297,10 @@ public class ProfileUtilities extends TranslatingUtilities { } } else c.addPiece(checkForNoChange(t, gen.new Piece((p.getValue().startsWith(corePath)? corePath: "")+ref, t.getWorkingCode(), null))); + if (isMustSupport(p) && e.getMustSupport()) { + c.addPiece(gen.new Piece(null, " ", null)); + c.addStyledText(translate("sd.table", "This profile must be supported"), "S", "white", "red", null, false); + } } } else { String tc = t.getWorkingCode(); @@ -3301,8 +3313,13 @@ public class ProfileUtilities extends TranslatingUtilities { } } else if (pkp != null && pkp.hasLinkFor(tc)) { c.addPiece(checkForNoChange(t, gen.new Piece(pkp.getLinkFor(corePath, tc), tc, null))); - } else + } else { c.addPiece(checkForNoChange(t, gen.new Piece(null, tc, null))); + } + if (isMustSupportDirect(t) && e.getMustSupport()) { + c.addPiece(gen.new Piece(null, " ", null)); + c.addStyledText(translate("sd.table", "This type must be supported"), "S", "white", "red", null, false); + } } } return c; @@ -3931,6 +3948,10 @@ public class ProfileUtilities extends TranslatingUtilities { c.getPieces().add(gen.new Piece(corePath+"datatypes.html#canonical", "canonical", null)); else c.getPieces().add(gen.new Piece(corePath+"references.html#Reference", "Reference", null)); + if (isMustSupportDirect(tr) && element.getMustSupport()) { + c.addPiece(gen.new Piece(null, " ", null)); + c.addStyledText(translate("sd.table", "This type must be supported"), "S", "white", "red", null, false); + } c.getPieces().add(gen.new Piece(null, "(", null)); } boolean first = true; @@ -3938,6 +3959,10 @@ public class ProfileUtilities extends TranslatingUtilities { if (!first) c.getPieces().add(gen.new Piece(null, " | ", null)); genTargetLink(gen, profileBaseFileName, corePath, c, tr, rt.getValue()); + if (isMustSupport(rt) && element.getMustSupport()) { + c.addPiece(gen.new Piece(null, " ", null)); + c.addStyledText(translate("sd.table", "This target must be supported"), "S", "white", "red", null, false); + } first = false; } if (first) @@ -3956,20 +3981,23 @@ public class ProfileUtilities extends TranslatingUtilities { choicerow.getCells().add(gen.new Cell()); choicerow.getCells().add(gen.new Cell(null, null, "", null, null)); choicerow.setIcon("icon_primitive.png", HierarchicalTableGenerator.TEXT_ICON_PRIMITIVE); - choicerow.getCells().add(gen.new Cell(null, corePath+"datatypes.html#"+t, sd.getType(), null, null)); - // } else if (definitions.getConstraints().contthnsKey(t)) { - // ProfiledType pt = definitions.getConstraints().get(t); - // choicerow.getCells().add(gen.new Cell(null, null, e.getName().replace("[x]", Utilities.capitalize(pt.getBaseType())), definitions.getTypes().containsKey(t) ? definitions.getTypes().get(t).getDefinition() : null, null)); - // choicerow.getCells().add(gen.new Cell()); - // choicerow.getCells().add(gen.new Cell(null, null, "", null, null)); - // choicerow.setIcon("icon_datatype.gif", HierarchicalTableGenerator.TEXT_ICON_DATATYPE); - // choicerow.getCells().add(gen.new Cell(null, definitions.getSrcFile(t)+".html#"+t.replace("*", "open"), t, null, null)); + Cell c = gen.new Cell(null, corePath+"datatypes.html#"+t, sd.getType(), null, null); + choicerow.getCells().add(c); + if (isMustSupport(tr) && element.getMustSupport()) { + c.addPiece(gen.new Piece(null, " ", null)); + c.addStyledText(translate("sd.table", "This type must be supported"), "S", "white", "red", null, false); + } } else { choicerow.getCells().add(gen.new Cell(null, null, tail(element.getPath()).replace("[x]", Utilities.capitalize(t)), sd.getDescription(), null)); choicerow.getCells().add(gen.new Cell()); choicerow.getCells().add(gen.new Cell(null, null, "", null, null)); choicerow.setIcon("icon_datatype.gif", HierarchicalTableGenerator.TEXT_ICON_DATATYPE); - choicerow.getCells().add(gen.new Cell(null, pkp.getLinkFor(corePath, t), sd.getType(), null, null)); + Cell c = gen.new Cell(null, pkp.getLinkFor(corePath, t), sd.getType(), null, null); + choicerow.getCells().add(c); + if (isMustSupport(tr) && element.getMustSupport()) { + c.addPiece(gen.new Piece(null, " ", null)); + c.addStyledText(translate("sd.table", "This type must be supported"), "S", "white", "red", null, false); + } } if (tr.hasProfile()) { Cell typeCell = choicerow.getCells().get(3); @@ -3982,6 +4010,10 @@ public class ProfileUtilities extends TranslatingUtilities { typeCell.addPiece(gen.new Piece(null, "?gen-e2?", null)); else typeCell.addPiece(gen.new Piece(psd.getUserString("path"), psd.getName(), psd.present())); + if (isMustSupport(pt) && element.getMustSupport()) { + typeCell.addPiece(gen.new Piece(null, " ", null)); + typeCell.addStyledText(translate("sd.table", "This profile must be supported"), "S", "white", "red", null, false); + } } typeCell.addPiece(gen.new Piece(null, ")", null)); @@ -6177,6 +6209,32 @@ public class ProfileUtilities extends TranslatingUtilities { return grp; } + public static boolean isMustSupportDirect(TypeRefComponent tr) { + return ("true".equals(ToolingExtensions.readStringExtension(tr, ToolingExtensions.EXT_MUST_SUPPORT))); + } + public static boolean isMustSupport(TypeRefComponent tr) { + if ("true".equals(ToolingExtensions.readStringExtension(tr, ToolingExtensions.EXT_MUST_SUPPORT))) { + return true; + } + if (isMustSupport(tr.getProfile())) { + return true; + } + return isMustSupport(tr.getTargetProfile()); + } + + public static boolean isMustSupport(List profiles) { + for (CanonicalType ct : profiles) { + if (isMustSupport(ct)) { + return true; + } + } + return false; + } + + + public static boolean isMustSupport(CanonicalType profile) { + return "true".equals(ToolingExtensions.readStringExtension(profile, ToolingExtensions.EXT_MUST_SUPPORT)); + } } \ No newline at end of file diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/ToolingExtensions.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/ToolingExtensions.java index 40f5f73f6..175fec654 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/ToolingExtensions.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/ToolingExtensions.java @@ -180,6 +180,7 @@ public class ToolingExtensions { public static final String EXT_OLD_CONCEPTMAP_EQUIVALENCE = "http://hl7.org/fhir/1.0/StructureDefinition/extension-ConceptMap.element.target.equivalence"; public static final String EXT_EXP_FRAGMENT = "http://hl7.org/fhir/tools/StructureDefinition/expansion-codesystem-fragment"; public static final String EXT_EXP_TOOCOSTLY = "http://hl7.org/fhir/StructureDefinition/valueset-toocostly"; + public static final String EXT_MUST_SUPPORT = "http://hl7.org/fhir/StructureDefinition/elementdefinition-type-must-support"; // specific extension helpers @@ -335,6 +336,8 @@ public class ToolingExtensions { return ((DecimalType) ex.getValue()).asStringValue(); if ((ex.getValue() instanceof MarkdownType)) return ((MarkdownType) ex.getValue()).getValue(); + if ((ex.getValue() instanceof PrimitiveType)) + return ((PrimitiveType) ex.getValue()).primitiveValue(); if (!(ex.getValue() instanceof StringType)) return null; return ((StringType) ex.getValue()).getValue(); 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 1d5359d76..4d9da697d 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 @@ -341,6 +341,8 @@ public class I18nConstants { public static final String RESOURCE_TYPE_MISMATCH_FOR___ = "Resource_type_mismatch_for___"; public static final String SAME_ID_ON_MULTIPLE_ELEMENTS__IN_ = "Same_id_on_multiple_elements__in_"; public static final String SD_MUST_HAVE_DERIVATION = "SD_MUST_HAVE_DERIVATION"; + public static final String SD_NESTED_MUST_SUPPORT_DIFF = "SD_NESTED_MUST_SUPPORT_DIFF"; + public static final String SD_NESTED_MUST_SUPPORT_SNAPSHOT = "SD_NESTED_MUST_SUPPORT_SNAPSHOT"; public static final String SEARCHPARAMETER_BASE_WRONG = "SEARCHPARAMETER_BASE_WRONG"; public static final String SEARCHPARAMETER_EXP_WRONG = "SEARCHPARAMETER_EXP_WRONG"; public static final String SEARCHPARAMETER_NOTFOUND = "SEARCHPARAMETER_NOTFOUND"; diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/turtle/Turtle.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/turtle/Turtle.java index a92f03c66..a555698a3 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/turtle/Turtle.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/turtle/Turtle.java @@ -384,12 +384,12 @@ public class Turtle { public String asHtml() throws Exception { StringBuilder b = new StringBuilder(); - b.append("
\r\n");
+    b.append("
\r\n");
     commitPrefixes(b);
     for (Section s : sections) {
       commitSection(b, s);
     }
-    b.append("
\r\n"); + b.append("
\r\n"); b.append("\r\n"); return b.toString(); } diff --git a/org.hl7.fhir.utilities/src/main/resources/Messages.properties b/org.hl7.fhir.utilities/src/main/resources/Messages.properties index 562e34887..18bee95a6 100644 --- a/org.hl7.fhir.utilities/src/main/resources/Messages.properties +++ b/org.hl7.fhir.utilities/src/main/resources/Messages.properties @@ -608,4 +608,7 @@ REFERENCE_REF_SUSPICIOUS = The syntax of the reference ''{0}'' looks incorrect, TYPE_SPECIFIC_CHECKS_DT_QTY_NO_ANNOTATIONS = UCUM Codes that contain human readable annotations like {0} can be misleading. Best Practice is not to use annotations in the UCUM code, and rather to make sure that Quantity.unit is correctly human readable XHTML_XHTML_ELEMENT_ILLEGAL_IN_PARA = Illegal element name inside in a paragraph in the XHTML (''{0}'') UNSUPPORTED_IDENTIFIER_PATTERN_PROPERTY_NOT_SUPPORTED_FOR_DISCRIMINATOR_FOR_SLICE = Unsupported property {3} on type {2} for pattern for discriminator({0}) for slice {1} -UNSUPPORTED_IDENTIFIER_PATTERN_NO_PROPERTY_NOT_SUPPORTED_FOR_DISCRIMINATOR_FOR_SLICE = Unsupported: no properties with values found on type {2} for pattern for discriminator({0}) for slice {1} \ No newline at end of file +UNSUPPORTED_IDENTIFIER_PATTERN_NO_PROPERTY_NOT_SUPPORTED_FOR_DISCRIMINATOR_FOR_SLICE = Unsupported: no properties with values found on type {2} for pattern for discriminator({0}) for slice {1} +SD_NESTED_MUST_SUPPORT_DIFF = The element {0} has types/profiles/targets that are marked as must support, but the element itself is not marked as must-support. The inner must-supports will be ignored unless the element inherits must-support = true +SD_NESTED_MUST_SUPPORT_SNAPSHOT = The element {0} has types/profiles/targets that are marked as must support, but the element itself is not marked as must-support + \ No newline at end of file diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/BaseValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/BaseValidator.java index 9e1bd5dd3..c36db51d3 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/BaseValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/BaseValidator.java @@ -296,9 +296,10 @@ public class BaseValidator { * Set this parameter to false if the validation does not pass * @return Returns thePass (in other words, returns true if the rule did not fail validation) */ - protected boolean hint(List errors, IssueType type, String path, boolean thePass, String msg) { + protected boolean hint(List errors, IssueType type, String path, boolean thePass, String theMessage, Object... theMessageArguments) { if (!thePass) { - addValidationMessage(errors, type, -1, -1, path, msg, IssueSeverity.INFORMATION, null); + String message = context.formatMessage(theMessage, theMessageArguments); + addValidationMessage(errors, type, -1, -1, path, message, IssueSeverity.INFORMATION, null); } return thePass; } 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 02aee0df3..0c7ab8330 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 @@ -483,7 +483,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat private boolean isKnownExtension(String url) { // Added structuredefinition-expression and following extensions explicitly because they weren't defined in the version of the spec they need to be used with - if ((allowExamples && (url.contains("example.org") || url.contains("acme.com"))) || url.contains("nema.org") || url.startsWith("http://hl7.org/fhir/tools/StructureDefinition/") || url.equals("http://hl7.org/fhir/StructureDefinition/structuredefinition-expression") || url.equals(VersionConvertorConstants.IG_DEPENDSON_PACKAGE_EXTENSION)) + if ((allowExamples && (url.contains("example.org") || url.contains("acme.com"))) || url.contains("nema.org") || url.startsWith("http://hl7.org/fhir/tools/StructureDefinition/") || url.equals("http://hl7.org/fhir/StructureDefinition/structuredefinition-expression")) return true; for (String s : extensionDomains) if (url.startsWith(s)) @@ -1521,6 +1521,8 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (extensionUrl.equals(profile.getUrl())) { rule(errors, IssueType.INVALID, element.line(), element.col(), path + "[url='" + url + "']", hasExtensionSlice(profile, url), I18nConstants.EXTENSION_EXT_SUBEXTENSION_INVALID, url, profile.getUrl()); } + } else if (SpecialExtensions.isKnownExtension(url)) { + ex = SpecialExtensions.getDefinition(url); } else if (rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, allowUnknownExtension(url), I18nConstants.EXTENSION_EXT_UNKNOWN_NOTHERE, url)) { hint(errors, IssueType.STRUCTURE, element.line(), element.col(), path, isKnownExtension(url), I18nConstants.EXTENSION_EXT_UNKNOWN, url); } @@ -1556,6 +1558,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat return ex; } + private boolean hasExtensionSlice(StructureDefinition profile, String sliceName) { for (ElementDefinition ed : profile.getSnapshot().getElement()) { if (ed.getPath().equals("Extension.extension.url") && ed.hasFixed() && sliceName.equals(ed.getFixed().primitiveValue())) { @@ -1933,7 +1936,8 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (fetcher != null) { boolean found; try { - found = isDefinitionURL(url) || (allowExamples && (url.contains("example.org") || url.contains("acme.com")) || url.contains("acme.org")) || (url.startsWith("http://hl7.org/fhir/tools")) || fetcher.resolveURL(appContext, path, url); + found = isDefinitionURL(url) || (allowExamples && (url.contains("example.org") || url.contains("acme.com")) || url.contains("acme.org")) || (url.startsWith("http://hl7.org/fhir/tools")) || fetcher.resolveURL(appContext, path, url) || + SpecialExtensions.isKnownExtension(url); } catch (IOException e1) { found = false; } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/SpecialExtensions.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/SpecialExtensions.java new file mode 100644 index 000000000..a51f75ef1 --- /dev/null +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/SpecialExtensions.java @@ -0,0 +1,39 @@ +package org.hl7.fhir.validation.instance; + +import java.io.IOException; +import java.io.InputStream; + +import org.hl7.fhir.convertors.VersionConvertorConstants; +import org.hl7.fhir.exceptions.FHIRFormatError; +import org.hl7.fhir.r5.formats.JsonParser; +import org.hl7.fhir.r5.formats.XmlParser; +import org.hl7.fhir.r5.model.StructureDefinition; +import org.hl7.fhir.utilities.Utilities; + +public class SpecialExtensions { + + // copied from R5 spec + private static final String MUST_SUPPORT_SOURCE = "{\"resourceType\" : \"StructureDefinition\",\"id\" : \"elementdefinition-type-must-support\",\"extension\" : [{\"url\" : \"http://hl7.org/fhir/StructureDefinition/structuredefinition-wg\",\"valueCode\" : \"fhir\"},{\"url\" : \"http://hl7.org/fhir/StructureDefinition/structuredefinition-fmm\",\"valueInteger\" : 1}],\"url\" : \"http://hl7.org/fhir/StructureDefinition/elementdefinition-type-must-support\",\"version\" : \"4.5.0\",\"name\" : \"type-must-support\",\"status\" : \"draft\",\"date\" : \"2015-02-28\",\"publisher\" : \"Health Level Seven, Inc. - FHIR Core WG\",\"contact\" : [{\"telecom\" : [{\"system\" : \"url\",\"value\" : \"http://hl7.org/special/committees/FHIR\"}]}],\"description\" : \"If true indicates that the specified type, profile or targetProfile must be supported by implementations.\",\"fhirVersion\" : \"4.5.0\",\"mapping\" : [{\"identity\" : \"rim\",\"uri\" : \"http://hl7.org/v3\",\"name\" : \"RIM Mapping\"}],\"kind\" : \"complex-type\",\"abstract\" : false,\"context\" : [{\"type\" : \"element\",\"expression\" : \"ElementDefinition.type\"},{\"type\" : \"element\",\"expression\" : \"ElementDefinition.type.profile\"},{\"type\" : \"element\",\"expression\" : \"ElementDefinition.type.targetProfile\"}],\"type\" : \"Extension\",\"baseDefinition\" : \"http://hl7.org/fhir/StructureDefinition/Extension\",\"derivation\" : \"constraint\",\"snapshot\" : {\"element\" : [{\"id\" : \"Extension\",\"path\" : \"Extension\",\"short\" : \"The specified type/profile/target must be supported by implementations\",\"definition\" : \"If true indicates that the specified type, profile or targetProfile must be supported by implementations.\",\"comment\" : \"An element may be labelled as must support. This extension clarifies which types/profiles/targetProfiles are must-support. It has no meaning if the element itself is not must-support. If the element is labelled must-support, and none of the options are labelled as must support, then an application must support at least one of the possible options, but is not required to support all of them.\",\"min\" : 0,\"max\" : \"1\",\"base\" : {\"path\" : \"Extension\",\"min\" : 0,\"max\" : \"*\"},\"constraint\" : [{\"key\" : \"ele-1\",\"severity\" : \"error\",\"human\" : \"All FHIR elements must have a @value or children\",\"expression\" : \"hasValue() or (children().count() > id.count())\",\"xpath\" : \"@value|f:*|h:div\",\"source\" : \"http://hl7.org/fhir/StructureDefinition/Element\"},{\"key\" : \"ext-1\",\"severity\" : \"error\",\"human\" : \"Must have either extensions or value[x], not both\",\"expression\" : \"extension.exists() != value.exists()\",\"xpath\" : \"exists(f:extension)!=exists(f:*[starts-with(local-name(.), 'value')])\",\"source\" : \"http://hl7.org/fhir/StructureDefinition/Extension\"}],\"isModifier\" : false},{\"id\" : \"Extension.id\",\"path\" : \"Extension.id\",\"representation\" : [\"xmlAttr\"],\"short\" : \"Unique id for inter-element referencing\",\"definition\" : \"Unique id for the element within a resource (for internal references). This may be any string value that does not contain spaces.\",\"min\" : 0,\"max\" : \"1\",\"base\" : {\"path\" : \"Element.id\",\"min\" : 0,\"max\" : \"1\"},\"type\" : [{\"extension\" : [{\"url\" : \"http://hl7.org/fhir/StructureDefinition/structuredefinition-fhir-type\",\"valueUri\" : \"string\"}],\"code\" : \"http://hl7.org/fhirpath/System.String\"}],\"isModifier\" : false,\"isSummary\" : false,\"mapping\" : [{\"identity\" : \"rim\",\"map\" : \"n/a\"}]},{\"id\" : \"Extension.extension\",\"path\" : \"Extension.extension\",\"slicing\" : {\"discriminator\" : [{\"type\" : \"value\",\"path\" : \"url\"}],\"description\" : \"Extensions are always sliced by (at least) url\",\"rules\" : \"open\"},\"short\" : \"Extension\",\"definition\" : \"An Extension\",\"min\" : 0,\"max\" : \"0\",\"base\" : {\"path\" : \"Element.extension\",\"min\" : 0,\"max\" : \"*\"},\"type\" : [{\"code\" : \"Extension\"}],\"constraint\" : [{\"key\" : \"ele-1\",\"severity\" : \"error\",\"human\" : \"All FHIR elements must have a @value or children\",\"expression\" : \"hasValue() or (children().count() > id.count())\",\"xpath\" : \"@value|f:*|h:div\",\"source\" : \"http://hl7.org/fhir/StructureDefinition/Element\"},{\"key\" : \"ext-1\",\"severity\" : \"error\",\"human\" : \"Must have either extensions or value[x], not both\",\"expression\" : \"extension.exists() != value.exists()\",\"xpath\" : \"exists(f:extension)!=exists(f:*[starts-with(local-name(.), \\\"value\\\")])\",\"source\" : \"http://hl7.org/fhir/StructureDefinition/Extension\"}],\"isModifier\" : false,\"isSummary\" : false},{\"id\" : \"Extension.url\",\"path\" : \"Extension.url\",\"representation\" : [\"xmlAttr\"],\"short\" : \"identifies the meaning of the extension\",\"definition\" : \"Source of the definition for the extension code - a logical name or a URL.\",\"comment\" : \"The definition may point directly to a computable or human-readable definition of the extensibility codes, or it may be a logical URI as declared in some other specification. The definition SHALL be a URI for the Structure Definition defining the extension.\",\"min\" : 1,\"max\" : \"1\",\"base\" : {\"path\" : \"Extension.url\",\"min\" : 1,\"max\" : \"1\"},\"type\" : [{\"extension\" : [{\"url\" : \"http://hl7.org/fhir/StructureDefinition/structuredefinition-fhir-type\",\"valueUri\" : \"uri\"}],\"code\" : \"http://hl7.org/fhirpath/System.String\"}],\"fixedUri\" : \"http://hl7.org/fhir/StructureDefinition/elementdefinition-type-must-support\",\"isModifier\" : false,\"isSummary\" : false,\"mapping\" : [{\"identity\" : \"rim\",\"map\" : \"N/A\"}]},{\"id\" : \"Extension.value[x]\",\"path\" : \"Extension.value[x]\",\"short\" : \"Value of extension\",\"definition\" : \"Value of extension - must be one of a constrained set of the data types (see [Extensibility](extensibility.html) for a list).\",\"min\" : 1,\"max\" : \"1\",\"base\" : {\"path\" : \"Extension.value[x]\",\"min\" : 0,\"max\" : \"1\"},\"type\" : [{\"code\" : \"boolean\"}],\"constraint\" : [{\"key\" : \"ele-1\",\"severity\" : \"error\",\"human\" : \"All FHIR elements must have a @value or children\",\"expression\" : \"hasValue() or (children().count() > id.count())\",\"xpath\" : \"@value|f:*|h:div\",\"source\" : \"http://hl7.org/fhir/StructureDefinition/Element\"}],\"isModifier\" : false,\"isSummary\" : false,\"mapping\" : [{\"identity\" : \"rim\",\"map\" : \"N/A\"}]}]},\"differential\" : {\"element\" : [{\"id\" : \"Extension\",\"path\" : \"Extension\",\"short\" : \"The specified type/profile/target must be supported by implementations\",\"definition\" : \"If true indicates that the specified type, profile or targetProfile must be supported by implementations.\",\"comment\" : \"An element may be labelled as must support. This extension clarifies which types/profiles/targetProfiles are must-support. It has no meaning if the element itself is not must-support. If the element is labelled must-support, and none of the options are labelled as must support, then an application must support at least one of the possible options, but is not required to support all of them.\",\"min\" : 0,\"max\" : \"1\"},{\"id\" : \"Extension.extension\",\"path\" : \"Extension.extension\",\"max\" : \"0\"},{\"id\" : \"Extension.url\",\"path\" : \"Extension.url\",\"fixedUri\" : \"http://hl7.org/fhir/StructureDefinition/elementdefinition-type-must-support\"},{\"id\" : \"Extension.value[x]\",\"path\" : \"Extension.value[x]\",\"min\" : 1,\"type\" : [{\"code\" : \"boolean\"}]}]}}"; + + public static boolean isKnownExtension(String url) { + return Utilities.existsInList(url, + "http://hl7.org/fhir/StructureDefinition/elementdefinition-type-must-support" + ); + } + + public static StructureDefinition getDefinition(String url) { + try { + switch (url) { + case "http://hl7.org/fhir/StructureDefinition/elementdefinition-type-must-support" : return makeMustSupport(); + default: return null; + } + } catch (Exception e) { + return null; + } + } + + private static StructureDefinition makeMustSupport() throws FHIRFormatError, IOException { + return (StructureDefinition) new JsonParser().parse(MUST_SUPPORT_SOURCE); + } + +} 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 d7dec41cd..f7631ef8b 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 @@ -28,6 +28,7 @@ import org.hl7.fhir.r5.model.StructureDefinition.TypeDerivationRule; import org.hl7.fhir.r5.model.SearchParameter; import org.hl7.fhir.r5.model.ValueSet; import org.hl7.fhir.r5.utils.FHIRPathEngine; +import org.hl7.fhir.r5.utils.ToolingExtensions; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.VersionUtilities; import org.hl7.fhir.utilities.i18n.I18nConstants; @@ -95,6 +96,69 @@ public class StructureDefinitionValidator extends BaseValidator { } catch (FHIRException | IOException e) { rule(errors, IssueType.EXCEPTION, stack.getLiteralPath(), false, I18nConstants.ERROR_GENERATING_SNAPSHOT, e.getMessage()); } + List differentials = src.getChildrenByName("differential"); + List snapshots = src.getChildrenByName("snapshot"); + for (Element differential : differentials) { + validateElementList(errors, differential, stack.push(differential, -1, null, null), false, snapshots.size() > 0); + } + for (Element snapshot : snapshots) { + validateElementList(errors, snapshot, stack.push(snapshot, -1, null, null), true, true); + } + } + + private void validateElementList(List errors, Element elementList, NodeStack stack, boolean snapshot, boolean hasSnapshot) { + List elements = elementList.getChildrenByName("element"); + int cc = 0; + for (Element element : elements) { + validateElementDefinition(errors, element, stack.push(element, cc, null, null), snapshot, hasSnapshot); + cc++; + } + } + + private void validateElementDefinition(List errors, Element element, NodeStack stack, boolean snapshot, boolean hasSnapshot) { + boolean typeMustSupport = false; + List types = element.getChildrenByName("type"); + for (Element type : types) { + if (hasMustSupportExtension(type)) { + typeMustSupport = true; + } + } + if (typeMustSupport) { + if (snapshot) { + rule(errors, IssueType.EXCEPTION, stack.getLiteralPath(), "true".equals(element.getChildValue("mustSupport")), I18nConstants.SD_NESTED_MUST_SUPPORT_SNAPSHOT, element.getNamedChildValue("path")); + } else { + hint(errors, IssueType.EXCEPTION, stack.getLiteralPath(), hasSnapshot || "true".equals(element.getChildValue("mustSupport")), I18nConstants.SD_NESTED_MUST_SUPPORT_DIFF, element.getNamedChildValue("path")); + } + } + } + + private boolean hasMustSupportExtension(Element type) { + if ("true".equals(getExtensionValue(type, ToolingExtensions.EXT_MUST_SUPPORT))) { + return true; + } + List profiles = type.getChildrenByName("profile"); + for (Element profile : profiles) { + if ("true".equals(getExtensionValue(profile, ToolingExtensions.EXT_MUST_SUPPORT))) { + return true; + } + } + profiles = type.getChildrenByName("targetProfile"); + for (Element profile : profiles) { + if ("true".equals(getExtensionValue(profile, ToolingExtensions.EXT_MUST_SUPPORT))) { + return true; + } + } + return false; + } + + private String getExtensionValue(Element element, String url) { + List extensions = element.getChildrenByName("extension"); + for (Element extension : extensions) { + if (url.equals(extension.getNamedChildValue("url"))) { + return extension.getNamedChildValue("value"); + } + } + return null; } private StructureDefinition loadAsSD(Element src) throws FHIRException, IOException { From 0d0caf3e84e762d0b4be7c9b606bd435d97bea30 Mon Sep 17 00:00:00 2001 From: markiantorno Date: Thu, 24 Sep 2020 19:38:03 +0000 Subject: [PATCH 42/73] Release: v5.1.14 Validator: * Add new validation for must-support on types / profiles / targets + improve Extension validation Other code changes: * Ensure "I" flag in profile table representation is not used just for infrastructural constraints * Render multiple values for properties in CodeSystems if they exist * Fix for npe rendering resources based on profiles * fix for use of "current" as version * hack for past bad package URLs * Add rendering for must support on types, profiles, targets * add when rendering turtle to HTML ***NO_CI*** --- org.hl7.fhir.convertors/pom.xml | 2 +- org.hl7.fhir.dstu2/pom.xml | 2 +- org.hl7.fhir.dstu2016may/pom.xml | 2 +- org.hl7.fhir.dstu3/pom.xml | 2 +- org.hl7.fhir.r4/pom.xml | 2 +- org.hl7.fhir.r5/pom.xml | 2 +- org.hl7.fhir.report/pom.xml | 2 +- org.hl7.fhir.utilities/pom.xml | 2 +- org.hl7.fhir.validation.cli/pom.xml | 2 +- org.hl7.fhir.validation/pom.xml | 2 +- pom.xml | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/org.hl7.fhir.convertors/pom.xml b/org.hl7.fhir.convertors/pom.xml index cee272fa6..b75553375 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 - 5.1.14-SNAPSHOT + 5.1.14 ../pom.xml diff --git a/org.hl7.fhir.dstu2/pom.xml b/org.hl7.fhir.dstu2/pom.xml index b851cfc3b..a1d516726 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 - 5.1.14-SNAPSHOT + 5.1.14 ../pom.xml diff --git a/org.hl7.fhir.dstu2016may/pom.xml b/org.hl7.fhir.dstu2016may/pom.xml index 4948e25d2..582130ab2 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 - 5.1.14-SNAPSHOT + 5.1.14 ../pom.xml diff --git a/org.hl7.fhir.dstu3/pom.xml b/org.hl7.fhir.dstu3/pom.xml index a0d999cae..67e68fcda 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 - 5.1.14-SNAPSHOT + 5.1.14 ../pom.xml diff --git a/org.hl7.fhir.r4/pom.xml b/org.hl7.fhir.r4/pom.xml index 21841a440..f13519f82 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 - 5.1.14-SNAPSHOT + 5.1.14 ../pom.xml diff --git a/org.hl7.fhir.r5/pom.xml b/org.hl7.fhir.r5/pom.xml index abbebd467..516968fe2 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 - 5.1.14-SNAPSHOT + 5.1.14 ../pom.xml diff --git a/org.hl7.fhir.report/pom.xml b/org.hl7.fhir.report/pom.xml index 90e45a22b..953a8f1e0 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 - 5.1.14-SNAPSHOT + 5.1.14 ../pom.xml diff --git a/org.hl7.fhir.utilities/pom.xml b/org.hl7.fhir.utilities/pom.xml index 382f03387..06984a18a 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 - 5.1.14-SNAPSHOT + 5.1.14 ../pom.xml diff --git a/org.hl7.fhir.validation.cli/pom.xml b/org.hl7.fhir.validation.cli/pom.xml index 1fd5a71b2..eb945bb36 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 - 5.1.14-SNAPSHOT + 5.1.14 ../pom.xml diff --git a/org.hl7.fhir.validation/pom.xml b/org.hl7.fhir.validation/pom.xml index 83a963927..998bc22c1 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 - 5.1.14-SNAPSHOT + 5.1.14 ../pom.xml diff --git a/pom.xml b/pom.xml index a0a6b5c09..e6916d4a1 100644 --- a/pom.xml +++ b/pom.xml @@ -13,7 +13,7 @@ each other. It is fine to bump the point version of this POM without affecting HAPI FHIR. --> - 5.1.14-SNAPSHOT + 5.1.14 5.1.0 From b93c13280d23a896eaa295105c9badbb3e44ee1a Mon Sep 17 00:00:00 2001 From: Mark Iantorno Date: Thu, 24 Sep 2020 15:59:39 -0400 Subject: [PATCH 43/73] Update RELEASE_NOTES.md --- RELEASE_NOTES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index fd314bfee..b5db1b91e 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -8,4 +8,4 @@ Other code changes: * fix for use of "current" as version * hack for past bad package URLs * Add rendering for must support on types, profiles, targets -* add when rendering turtle to HTML \ No newline at end of file +* add code when rendering turtle to HTML From 31e4a01104988d19ff21fb580cf6450037560902 Mon Sep 17 00:00:00 2001 From: Mark Iantorno Date: Thu, 24 Sep 2020 16:03:33 -0400 Subject: [PATCH 44/73] Update RELEASE_NOTES.md --- RELEASE_NOTES.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index b5db1b91e..7ae98ef71 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,7 +1,7 @@ -Validator: -* Add new validation for must-support on types / profiles / targets + improve Extension validation +Validator +* Add new validation for must-support on types, profiles, targets and improve Extension validation -Other code changes: +Other code changes * Ensure "I" flag in profile table representation is not used just for infrastructural constraints * Render multiple values for properties in CodeSystems if they exist * Fix for npe rendering resources based on profiles From eaa747fa67dff2f3c437d134b05e21404eb35f84 Mon Sep 17 00:00:00 2001 From: Mark Iantorno Date: Thu, 24 Sep 2020 16:07:43 -0400 Subject: [PATCH 45/73] Update RELEASE_NOTES.md --- RELEASE_NOTES.md | 1 - 1 file changed, 1 deletion(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 7ae98ef71..d0017f70d 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,6 +1,5 @@ Validator * Add new validation for must-support on types, profiles, targets and improve Extension validation - Other code changes * Ensure "I" flag in profile table representation is not used just for infrastructural constraints * Render multiple values for properties in CodeSystems if they exist From e10c52a70b26675de93c5fb559ca76703b26ffbd Mon Sep 17 00:00:00 2001 From: Mark Iantorno Date: Thu, 24 Sep 2020 16:42:46 -0400 Subject: [PATCH 46/73] Update RELEASE_NOTES.md --- RELEASE_NOTES.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index d0017f70d..ab35894c7 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,10 +1,10 @@ Validator * Add new validation for must-support on types, profiles, targets and improve Extension validation Other code changes -* Ensure "I" flag in profile table representation is not used just for infrastructural constraints +* Ensure I flag in profile table representation is not used just for infrastructural constraints * Render multiple values for properties in CodeSystems if they exist * Fix for npe rendering resources based on profiles -* fix for use of "current" as version +* fix for use of current as version * hack for past bad package URLs * Add rendering for must support on types, profiles, targets * add code when rendering turtle to HTML From 4da20d24fc517142c4141f3dd0086dc946def9b3 Mon Sep 17 00:00:00 2001 From: Mark Iantorno Date: Thu, 24 Sep 2020 16:43:15 -0400 Subject: [PATCH 47/73] Update RELEASE_NOTES.md --- RELEASE_NOTES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index ab35894c7..ba31a91a2 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,5 +1,6 @@ Validator * Add new validation for must-support on types, profiles, targets and improve Extension validation + Other code changes * Ensure I flag in profile table representation is not used just for infrastructural constraints * Render multiple values for properties in CodeSystems if they exist From b7183f005c4da5e5c03600c5ee03141671c26a5c Mon Sep 17 00:00:00 2001 From: markiantorno Date: Thu, 24 Sep 2020 20:45:19 +0000 Subject: [PATCH 48/73] Updating version to: 5.1.15-SNAPSHOT and incrementing test cases dependency. --- RELEASE_NOTES.md | 11 ----------- org.hl7.fhir.convertors/pom.xml | 2 +- org.hl7.fhir.dstu2/pom.xml | 2 +- org.hl7.fhir.dstu2016may/pom.xml | 2 +- org.hl7.fhir.dstu3/pom.xml | 2 +- org.hl7.fhir.r4/pom.xml | 2 +- org.hl7.fhir.r5/pom.xml | 2 +- org.hl7.fhir.report/pom.xml | 2 +- org.hl7.fhir.utilities/pom.xml | 2 +- org.hl7.fhir.validation.cli/pom.xml | 2 +- org.hl7.fhir.validation/pom.xml | 2 +- pom.xml | 2 +- 12 files changed, 11 insertions(+), 22 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index ba31a91a2..e69de29bb 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,11 +0,0 @@ -Validator -* Add new validation for must-support on types, profiles, targets and improve Extension validation - -Other code changes -* Ensure I flag in profile table representation is not used just for infrastructural constraints -* Render multiple values for properties in CodeSystems if they exist -* Fix for npe rendering resources based on profiles -* fix for use of current as version -* hack for past bad package URLs -* Add rendering for must support on types, profiles, targets -* add code when rendering turtle to HTML diff --git a/org.hl7.fhir.convertors/pom.xml b/org.hl7.fhir.convertors/pom.xml index b75553375..de428c64f 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 - 5.1.14 + 5.1.15-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.dstu2/pom.xml b/org.hl7.fhir.dstu2/pom.xml index a1d516726..808694ad4 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 - 5.1.14 + 5.1.15-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.dstu2016may/pom.xml b/org.hl7.fhir.dstu2016may/pom.xml index 582130ab2..8d0bd06ca 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 - 5.1.14 + 5.1.15-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.dstu3/pom.xml b/org.hl7.fhir.dstu3/pom.xml index 67e68fcda..bc0d6d442 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 - 5.1.14 + 5.1.15-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.r4/pom.xml b/org.hl7.fhir.r4/pom.xml index f13519f82..bfb12c7b0 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 - 5.1.14 + 5.1.15-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.r5/pom.xml b/org.hl7.fhir.r5/pom.xml index 516968fe2..deb8ae08d 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 - 5.1.14 + 5.1.15-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.report/pom.xml b/org.hl7.fhir.report/pom.xml index 953a8f1e0..ee6c9733e 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 - 5.1.14 + 5.1.15-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.utilities/pom.xml b/org.hl7.fhir.utilities/pom.xml index 06984a18a..76ce62bf3 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 - 5.1.14 + 5.1.15-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.validation.cli/pom.xml b/org.hl7.fhir.validation.cli/pom.xml index eb945bb36..4b31aa9bc 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 - 5.1.14 + 5.1.15-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.validation/pom.xml b/org.hl7.fhir.validation/pom.xml index 998bc22c1..b2c2a2747 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 - 5.1.14 + 5.1.15-SNAPSHOT ../pom.xml diff --git a/pom.xml b/pom.xml index e6916d4a1..db328cc8f 100644 --- a/pom.xml +++ b/pom.xml @@ -13,7 +13,7 @@ each other. It is fine to bump the point version of this POM without affecting HAPI FHIR. --> - 5.1.14 + 5.1.15-SNAPSHOT 5.1.0 From 4979a03140684e060ee56631ba89b35427f4e313 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Fri, 25 Sep 2020 14:59:12 +1000 Subject: [PATCH 49/73] fix rendering problems with languages in value sets --- .../hl7/fhir/r5/context/CanonicalResourceManager.java | 1 + .../org/hl7/fhir/r5/renderers/ValueSetRenderer.java | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/CanonicalResourceManager.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/CanonicalResourceManager.java index 289f7b52d..d9893d099 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/CanonicalResourceManager.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/CanonicalResourceManager.java @@ -220,6 +220,7 @@ public class CanonicalResourceManager { if (enforceUniqueId && map.containsKey(cr.getId())) { drop(cr.getId()); } + // special case logic for UTG support prior to version 5 if (cr.getPackageInfo() != null && cr.getPackageInfo().getId().startsWith("hl7.terminology")) { List> toDrop = new ArrayList<>(); 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 85b238893..94ff7037f 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 @@ -234,6 +234,7 @@ public class ValueSetRenderer extends TerminologyRenderer { } if (doDefinition) { tr.td().b().tx("Definition"); + doLangs = false; } else { // if we're not doing definitions and we don't have too many languages, we'll do them in line if (langs.size() < MAX_LANGS_IN_LINE) { @@ -260,9 +261,9 @@ public class ValueSetRenderer extends TerminologyRenderer { x.para().b().tx("Additional Language Displays"); t = x.table( "codes"); tr = t.tr(); - tdDisp.b().tx("Code"); + tr.td().b().tx("Code"); for (String lang : langs) { - tdDisp.b().addText(describeLang(lang)); + tr.td().b().addText(describeLang(lang)); } for (ValueSetExpansionContainsComponent c : vs.getExpansion().getContains()) { addLanguageRow(c, t, langs); @@ -482,7 +483,6 @@ public class ValueSetRenderer extends TerminologyRenderer { if ("1.0m".equals(v)) return "Jul 1999"; if ("1.0l".equals(v)) return "Jan 1998"; if ("1.0ja".equals(v)) return "Oct 1997"; - return null; } @@ -662,7 +662,9 @@ public class ValueSetRenderer extends TerminologyRenderer { td.i().tx("("+mapping.comp.getComment()+")"); } } - addLangaugesToRow(c, langs, tr); + if (doLangs) { + addLangaugesToRow(c, langs, tr); + } for (ValueSetExpansionContainsComponent cc : c.getContains()) { addExpansionRowToTable(t, cc, i+1, doLevel, doSystem, doDefinition, maps, allCS, langs, doLangs); } From 28e7a191259aaeecc54ae1f8104d92295557347d Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Fri, 25 Sep 2020 15:00:10 +1000 Subject: [PATCH 50/73] Change warnings about invalid codes to hints in retired value sets --- .../org/hl7/fhir/validation/BaseValidator.java | 15 +++++++++++++++ .../instance/type/ValueSetValidator.java | 14 +++++++------- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/BaseValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/BaseValidator.java index c36db51d3..8e7b585a7 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/BaseValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/BaseValidator.java @@ -529,6 +529,21 @@ public class BaseValidator { return thePass; } + /** + * Test a rule and add a {@link IssueSeverity#WARNING} validation message if the validation fails + * + * @param thePass + * Set this parameter to false if the validation does not pass + * @return Returns thePass (in other words, returns true if the rule did not fail validation) + */ + protected boolean warningOrHint(List errors, IssueType type, String path, boolean thePass, boolean warning, String msg, Object... theMessageArguments) { + if (!thePass) { + String message = context.formatMessage(msg, theMessageArguments); + addValidationMessage(errors, type, -1, -1, path, message, warning ? IssueSeverity.WARNING : IssueSeverity.INFORMATION, null); + } + return thePass; + } + /** * Test a rule and add a {@link IssueSeverity#WARNING} validation message if the validation fails * diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ValueSetValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ValueSetValidator.java index a10173f81..b3d4c0e3c 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ValueSetValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ValueSetValidator.java @@ -56,28 +56,28 @@ public class ValueSetValidator extends BaseValidator { List composes = vs.getChildrenByName("compose"); int cc = 0; for (Element compose : composes) { - validateValueSetCompose(errors, compose, stack.push(compose, cc, null, null), vs.getNamedChildValue("url")); + validateValueSetCompose(errors, compose, stack.push(compose, cc, null, null), vs.getNamedChildValue("url"), "retired".equals(vs.getNamedChildValue("url"))); cc++; } } } - private void validateValueSetCompose(List errors, Element compose, NodeStack stack, String vsid) { + private void validateValueSetCompose(List errors, Element compose, NodeStack stack, String vsid, boolean retired) { List includes = compose.getChildrenByName("include"); int ci = 0; for (Element include : includes) { - validateValueSetInclude(errors, include, stack.push(include, ci, null, null), vsid); + validateValueSetInclude(errors, include, stack.push(include, ci, null, null), vsid, retired); ci++; } List excludes = compose.getChildrenByName("exclude"); int ce = 0; for (Element exclude : excludes) { - validateValueSetInclude(errors, exclude, stack.push(exclude, ce, null, null), vsid); + validateValueSetInclude(errors, exclude, stack.push(exclude, ce, null, null), vsid, retired); ce++; } } - private void validateValueSetInclude(List errors, Element include, NodeStack stack, String vsid) { + private void validateValueSetInclude(List errors, Element include, NodeStack stack, String vsid, boolean retired) { String system = include.getChildValue("system"); String version = include.getChildValue("version"); List valuesets = include.getChildrenByName("valueSet"); @@ -125,9 +125,9 @@ public class ValueSetValidator extends BaseValidator { } for (VSCodingValidationRequest cv : batch) { if (version == null) { - warning(errors, IssueType.BUSINESSRULE, cv.getStack().getLiteralPath(), cv.getResult().isOk(), I18nConstants.VALUESET_INCLUDE_INVALID_CONCEPT_CODE, system, cv.getCoding().getCode()); + warningOrHint(errors, IssueType.BUSINESSRULE, cv.getStack().getLiteralPath(), cv.getResult().isOk(), !retired, I18nConstants.VALUESET_INCLUDE_INVALID_CONCEPT_CODE, system, cv.getCoding().getCode()); } else { - warning(errors, IssueType.BUSINESSRULE, cv.getStack().getLiteralPath(), cv.getResult().isOk(), I18nConstants.VALUESET_INCLUDE_INVALID_CONCEPT_CODE_VER, system, version, cv.getCoding().getCode()); + warningOrHint(errors, IssueType.BUSINESSRULE, cv.getStack().getLiteralPath(), cv.getResult().isOk(), !retired, I18nConstants.VALUESET_INCLUDE_INVALID_CONCEPT_CODE_VER, system, version, cv.getCoding().getCode()); } } } From 1bdf49c7a372fbd9a13a9154d537ae56781a4dac Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Fri, 25 Sep 2020 15:00:43 +1000 Subject: [PATCH 51/73] Fix bugs loading content to validate from hapi servers --- .../hl7/fhir/validation/ValidationEngine.java | 63 ++++++++++++------- 1 file changed, 41 insertions(+), 22 deletions(-) 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 d01ed9700..3a21f7591 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 @@ -642,18 +642,26 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst // ok, having tried all that... now we'll just try to access it directly byte[] cnt; - if (stream == null) - cnt = fetchFromUrlSpecific(src, "application/json", true); - else + List errors = new ArrayList<>(); + if (stream != null) { cnt = TextFile.streamToBytes(stream); - + } else { + cnt = fetchFromUrlSpecific(src, "application/json", true, errors); + if (cnt == null) { + cnt = fetchFromUrlSpecific(src, "application/xml", true, errors); + } + } + if (cnt == null) { + throw new FHIRException("Unable to fetch content from "+src+" ("+errors.toString()+")"); + + } FhirFormat fmt = checkIsResource(cnt, src); if (fmt != null) { Map res = new HashMap(); res.put(Utilities.changeFileExt(src, "."+fmt.getExtension()), cnt); return res; } - throw new FHIRException("Unable to find/resolve/read -ig "+src); + throw new FHIRException("Unable to read content from "+src+": cannot determine format"); } private Map fetchVersionFromUrl(String src, boolean explore, VersionSourceInformation versions) throws FHIRException, IOException { @@ -687,7 +695,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst // ok, having tried all that... now we'll just try to access it directly byte[] cnt; if (stream == null) - cnt = fetchFromUrlSpecific(src, "application/json", true); + cnt = fetchFromUrlSpecific(src, "application/json", true, null); else cnt = TextFile.streamToBytes(stream); @@ -713,13 +721,24 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst } } - private byte[] fetchFromUrlSpecific(String source, String contentType, boolean optional) throws FHIRException, IOException { + private byte[] fetchFromUrlSpecific(String source, String contentType, boolean optional, List errors) throws FHIRException, IOException { try { - URL url = new URL(source+"?nocache=" + System.currentTimeMillis()); - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setRequestProperty("Accept", contentType); - return TextFile.streamToBytes(conn.getInputStream()); + try { + // try with cache-busting option and then try withhout in case the server doesn't support that + URL url = new URL(source+"?nocache=" + System.currentTimeMillis()); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setRequestProperty("Accept", contentType); + return TextFile.streamToBytes(conn.getInputStream()); + } catch (Exception e) { + URL url = new URL(source); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setRequestProperty("Accept", contentType); + return TextFile.streamToBytes(conn.getInputStream()); + } } catch (IOException e) { + if (errors != null) { + errors.add("Error accessing "+source+": "+e.getMessage()); + } if (optional) return null; else @@ -1135,8 +1154,8 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst FhirFormat cntType = null; } - public Content loadContent(String source, String opName) throws FHIRException, IOException { - Map s = loadIgSource(source, false, false); + public Content loadContent(String source, String opName, boolean asIg) throws FHIRException, IOException { + Map s = loadIgSource(source, false, asIg); Content res = new Content(); if (s.size() != 1) throw new FHIRException("Unable to find resource " + source + " to "+opName); @@ -1192,7 +1211,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst InstanceValidator validator = getValidator(); for (String ref : refs) { - Content cnt = loadContent(ref, "validate"); + Content cnt = loadContent(ref, "validate", false); List messages = new ArrayList(); Element e = null; try { @@ -1264,7 +1283,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst List refs = new ArrayList(); handleSources(sources, refs); for (String ref : refs) { - Content cnt = loadContent(ref, "validate"); + Content cnt = loadContent(ref, "validate", false); String s = TextFile.bytesToString(cnt.focus); if (s.contains("http://hl7.org/fhir/3.0")) { versions.see("3.0", "Profile in "+ref); @@ -1293,7 +1312,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst TimeTracker.Session tts = context.clock().start("validation"); context.clock().milestone(); System.out.print(" Validate " + ref); - Content cnt = loadContent(ref, "validate"); + Content cnt = loadContent(ref, "validate", false); try { OperationOutcome outcome = validate(ref, cnt.focus, cnt.cntType, profiles); ToolingExtensions.addStringExtension(outcome, ToolingExtensions.EXT_OO_FILE, ref); @@ -1485,7 +1504,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst } public org.hl7.fhir.r5.elementmodel.Element transform(String source, String map) throws FHIRException, IOException { - Content cnt = loadContent(source, "validate"); + Content cnt = loadContent(source, "validate", false); return transform(cnt.focus, cnt.cntType, map); } @@ -1530,7 +1549,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst } public DomainResource generate(String source, String version) throws FHIRException, IOException, EOperationOutcome { - Content cnt = loadContent(source, "validate"); + Content cnt = loadContent(source, "validate", false); Resource res = loadResourceByVersion(version, cnt.focus, source); RenderingContext rc = new RenderingContext(context, null, null, "http://hl7.org/fhir", "", null, ResourceRendererMode.RESOURCE); RendererFactory.factory(res, rc).render((DomainResource) res); @@ -1538,20 +1557,20 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst } public void convert(String source, String output) throws FHIRException, IOException { - Content cnt = loadContent(source, "validate"); + Content cnt = loadContent(source, "validate", false); Element e = Manager.parse(context, new ByteArrayInputStream(cnt.focus), cnt.cntType); Manager.compose(context, e, new FileOutputStream(output), (output.endsWith(".json") ? FhirFormat.JSON : FhirFormat.XML), OutputStyle.PRETTY, null); } public String evaluateFhirPath(String source, String expression) throws FHIRException, IOException { - Content cnt = loadContent(source, "validate"); + Content cnt = loadContent(source, "validate", false); FHIRPathEngine fpe = new FHIRPathEngine(context); Element e = Manager.parse(context, new ByteArrayInputStream(cnt.focus), cnt.cntType); return fpe.evaluateToString(e, expression); } public StructureDefinition snapshot(String source, String version) throws FHIRException, IOException { - Content cnt = loadContent(source, "validate"); + Content cnt = loadContent(source, "validate", false); Resource res = loadResourceByVersion(version, cnt.focus, Utilities.getFileNameForName(source)); if (!(res instanceof StructureDefinition)) @@ -2054,7 +2073,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst } public byte[] transformVersion(String source, String targetVer, FhirFormat format, Boolean canDoNative) throws FHIRException, IOException, Exception { - Content cnt = loadContent(source, "validate"); + Content cnt = loadContent(source, "validate", false); org.hl7.fhir.r5.elementmodel.Element src = Manager.parse(context, new ByteArrayInputStream(cnt.focus), cnt.cntType); // if the src has a url, we try to use the java code From 7af4321f54e1b1e18b29ef7996787d02b5971caa Mon Sep 17 00:00:00 2001 From: Mark Iantorno Date: Fri, 25 Sep 2020 15:37:05 -0400 Subject: [PATCH 52/73] Update master-branch-pipeline.yml for Azure Pipelines Changing pipeline to deploy to deploy to GitHub packages STAGING. [skip ci] --- master-branch-pipeline.yml | 43 +++++++++++++++----------------------- 1 file changed, 17 insertions(+), 26 deletions(-) diff --git a/master-branch-pipeline.yml b/master-branch-pipeline.yml index 161b17f26..dc501da8e 100644 --- a/master-branch-pipeline.yml +++ b/master-branch-pipeline.yml @@ -11,6 +11,7 @@ pool: variables: - group: PGP_VAR_GROUP - group: SONATYPE_VAR_GROUP +- group: GIT_VAR_GROUP steps: # We need a valid signing key. @@ -43,37 +44,17 @@ steps: xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd"> + + github + $(GIT_USER_NAME) + $(GIT_PAT) + ossrh $(SONATYPE_USER) $(SONATYPE_PASS) - - sonatype-nexus-snapshots - $(SONATYPE_USER) - $(SONATYPE_PASS) - - - sonatype-nexus-staging - $(SONATYPE_USER) - $(SONATYPE_PASS) - - - $(PGP_KEYNAME) - $(PGP_PASSPHRASE) - - - - release - - true - - - $(PGP_KEYNAME) - - - EOL displayName: 'Create .mvn/settings.xml' @@ -85,5 +66,15 @@ steps: inputs: mavenPomFile: '$(System.DefaultWorkingDirectory)/pom.xml' goals: deploy - options: '--settings $(System.DefaultWorkingDirectory)/settings.xml -Pdeploy' + options: '--settings $(System.DefaultWorkingDirectory)/settings.xml -DdeployToSonatype' + publishJUnitResults: false + + # Deploy the SNAPSHOT artifact to GitHub packages. + # This is done for the master branch merges only. + - task: Maven@3 + displayName: 'Deploy $(module) to Sonatype staging' + inputs: + mavenPomFile: '$(System.DefaultWorkingDirectory)/pom.xml' + goals: deploy + options: '--settings $(System.DefaultWorkingDirectory)/settings.xml -Dmaven.test.skip -DdeployToGitHub' publishJUnitResults: false From df43f1d94f36bfe1f3d8b8c6a15f7737729c6e70 Mon Sep 17 00:00:00 2001 From: Mark Iantorno Date: Fri, 25 Sep 2020 16:42:06 -0400 Subject: [PATCH 53/73] Adding back in pgp passphrase ***NO_CI*** --- master-branch-pipeline.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/master-branch-pipeline.yml b/master-branch-pipeline.yml index dc501da8e..629536de3 100644 --- a/master-branch-pipeline.yml +++ b/master-branch-pipeline.yml @@ -54,6 +54,10 @@ steps: $(SONATYPE_USER) $(SONATYPE_PASS) + + $(PGP_KEYNAME) + $(PGP_PASSPHRASE) + EOL From 90c923720a760008a216207de076e56cd9552ba1 Mon Sep 17 00:00:00 2001 From: Mark Iantorno Date: Fri, 25 Sep 2020 16:47:46 -0400 Subject: [PATCH 54/73] Adding deployment profile with PGP key ***NO_CI*** --- master-branch-pipeline.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/master-branch-pipeline.yml b/master-branch-pipeline.yml index 629536de3..3708aba4b 100644 --- a/master-branch-pipeline.yml +++ b/master-branch-pipeline.yml @@ -59,6 +59,17 @@ steps: $(PGP_PASSPHRASE) + + + release + + true + + + $(PGP_KEYNAME) + + + EOL displayName: 'Create .mvn/settings.xml' From 6936ed731cae0defce6b7f54efc9b5ae1ccf54eb Mon Sep 17 00:00:00 2001 From: Mark Iantorno Date: Fri, 25 Sep 2020 16:49:03 -0400 Subject: [PATCH 55/73] GitHub packages (#357) * changes to enable publishing to both github packages and sonatype --- RELEASE_NOTES.md | 5 +++ pom.xml | 93 ++++++++++++++++++++++++++++++++++++------------ 2 files changed, 76 insertions(+), 22 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index e69de29bb..fa5af8181 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -0,0 +1,5 @@ +CI/CD: + +* Restructured pom files +* Added profiles for deploying to both GitHub packages, and SonatypeOSS + diff --git a/pom.xml b/pom.xml index db328cc8f..5f601a1db 100644 --- a/pom.xml +++ b/pom.xml @@ -13,7 +13,9 @@ each other. It is fine to bump the point version of this POM without affecting HAPI FHIR. --> + org.hl7.fhir.core 5.1.15-SNAPSHOT + pom 5.1.0 @@ -23,9 +25,6 @@ 0.8.5 - org.hl7.fhir.core - pom - HL7 Core Artifacts @@ -47,13 +46,6 @@ org.hl7.fhir.report - - - ossrh - https://oss.sonatype.org/content/repositories/snapshots - - - @@ -318,17 +310,6 @@ - - org.sonatype.plugins - nexus-staging-maven-plugin - 1.6.7 - true - - ossrh - https://oss.sonatype.org/ - true - - org.apache.maven.plugins maven-deploy-plugin @@ -338,7 +319,23 @@ - deploy + github-repo + + false + + deployToGitHub + + + + + github + https://maven.pkg.github.com/hapifhir/org.hl7.fhir.core + + + github + https://maven.pkg.github.com/hapifhir/org.hl7.fhir.core + + @@ -362,5 +359,57 @@ + + ossrh-repo + + false + + deployToSonatype + + + + + ossrh + https://oss.sonatype.org/content/repositories/snapshots + + + ossrh + https://oss.sonatype.org/service/local/staging/deploy/maven2/ + + + + + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.7 + true + + ossrh + https://oss.sonatype.org/ + true + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.6 + + + sign-artifacts + verify + + sign + + + ${gpg.keyname} + ${gpg.keyname} + + + + + + + From 6d4b3416cddb6e97a582240d108e0f4d138ffe28 Mon Sep 17 00:00:00 2001 From: Mark Iantorno Date: Fri, 25 Sep 2020 22:08:58 +0000 Subject: [PATCH 56/73] Updating test case dependency to v1.1.44 ***NO_CI*** --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5f601a1db..3b879d49c 100644 --- a/pom.xml +++ b/pom.xml @@ -19,7 +19,7 @@ 5.1.0 - 1.1.43-SNAPSHOT + 1.1.44 5.6.2 3.0.0-M4 0.8.5 From 5bb59c3b82652b0794ee37d2c26517ef48821038 Mon Sep 17 00:00:00 2001 From: markiantorno Date: Fri, 25 Sep 2020 23:49:45 +0000 Subject: [PATCH 57/73] Release: v5.1.15 CI/CD: * Restructured pom files * Added profiles for deploying to both GitHub packages, and SonatypeOSS ***NO_CI*** --- org.hl7.fhir.convertors/pom.xml | 2 +- org.hl7.fhir.dstu2/pom.xml | 2 +- org.hl7.fhir.dstu2016may/pom.xml | 2 +- org.hl7.fhir.dstu3/pom.xml | 2 +- org.hl7.fhir.r4/pom.xml | 2 +- org.hl7.fhir.r5/pom.xml | 2 +- org.hl7.fhir.report/pom.xml | 2 +- org.hl7.fhir.utilities/pom.xml | 2 +- org.hl7.fhir.validation.cli/pom.xml | 2 +- org.hl7.fhir.validation/pom.xml | 2 +- pom.xml | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/org.hl7.fhir.convertors/pom.xml b/org.hl7.fhir.convertors/pom.xml index de428c64f..a440c6a73 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 - 5.1.15-SNAPSHOT + 5.1.15 ../pom.xml diff --git a/org.hl7.fhir.dstu2/pom.xml b/org.hl7.fhir.dstu2/pom.xml index 808694ad4..61ac91c67 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 - 5.1.15-SNAPSHOT + 5.1.15 ../pom.xml diff --git a/org.hl7.fhir.dstu2016may/pom.xml b/org.hl7.fhir.dstu2016may/pom.xml index 8d0bd06ca..df35f49e2 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 - 5.1.15-SNAPSHOT + 5.1.15 ../pom.xml diff --git a/org.hl7.fhir.dstu3/pom.xml b/org.hl7.fhir.dstu3/pom.xml index bc0d6d442..c6cde693f 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 - 5.1.15-SNAPSHOT + 5.1.15 ../pom.xml diff --git a/org.hl7.fhir.r4/pom.xml b/org.hl7.fhir.r4/pom.xml index bfb12c7b0..d8b4d619c 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 - 5.1.15-SNAPSHOT + 5.1.15 ../pom.xml diff --git a/org.hl7.fhir.r5/pom.xml b/org.hl7.fhir.r5/pom.xml index deb8ae08d..242bcf844 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 - 5.1.15-SNAPSHOT + 5.1.15 ../pom.xml diff --git a/org.hl7.fhir.report/pom.xml b/org.hl7.fhir.report/pom.xml index ee6c9733e..c1d9c4d64 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 - 5.1.15-SNAPSHOT + 5.1.15 ../pom.xml diff --git a/org.hl7.fhir.utilities/pom.xml b/org.hl7.fhir.utilities/pom.xml index 76ce62bf3..ba3a019d9 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 - 5.1.15-SNAPSHOT + 5.1.15 ../pom.xml diff --git a/org.hl7.fhir.validation.cli/pom.xml b/org.hl7.fhir.validation.cli/pom.xml index 4b31aa9bc..c68842aaa 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 - 5.1.15-SNAPSHOT + 5.1.15 ../pom.xml diff --git a/org.hl7.fhir.validation/pom.xml b/org.hl7.fhir.validation/pom.xml index b2c2a2747..10a9c28d4 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 - 5.1.15-SNAPSHOT + 5.1.15 ../pom.xml diff --git a/pom.xml b/pom.xml index 3b879d49c..d076236ed 100644 --- a/pom.xml +++ b/pom.xml @@ -14,7 +14,7 @@ HAPI FHIR. --> org.hl7.fhir.core - 5.1.15-SNAPSHOT + 5.1.15 pom From afa46ebe7c34ebea92a3e6c3d616788014df185b Mon Sep 17 00:00:00 2001 From: markiantorno Date: Sat, 26 Sep 2020 00:15:47 +0000 Subject: [PATCH 58/73] Updating version to: 5.1.16-SNAPSHOT and incrementing test cases dependency. --- RELEASE_NOTES.md | 5 ----- org.hl7.fhir.convertors/pom.xml | 2 +- org.hl7.fhir.dstu2/pom.xml | 2 +- org.hl7.fhir.dstu2016may/pom.xml | 2 +- org.hl7.fhir.dstu3/pom.xml | 2 +- org.hl7.fhir.r4/pom.xml | 2 +- org.hl7.fhir.r5/pom.xml | 2 +- org.hl7.fhir.report/pom.xml | 2 +- org.hl7.fhir.utilities/pom.xml | 2 +- org.hl7.fhir.validation.cli/pom.xml | 2 +- org.hl7.fhir.validation/pom.xml | 2 +- pom.xml | 2 +- 12 files changed, 11 insertions(+), 16 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index fa5af8181..e69de29bb 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,5 +0,0 @@ -CI/CD: - -* Restructured pom files -* Added profiles for deploying to both GitHub packages, and SonatypeOSS - diff --git a/org.hl7.fhir.convertors/pom.xml b/org.hl7.fhir.convertors/pom.xml index a440c6a73..efecd1e44 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 - 5.1.15 + 5.1.16-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.dstu2/pom.xml b/org.hl7.fhir.dstu2/pom.xml index 61ac91c67..fb0ee362b 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 - 5.1.15 + 5.1.16-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.dstu2016may/pom.xml b/org.hl7.fhir.dstu2016may/pom.xml index df35f49e2..ab92b63cc 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 - 5.1.15 + 5.1.16-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.dstu3/pom.xml b/org.hl7.fhir.dstu3/pom.xml index c6cde693f..731ae419f 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 - 5.1.15 + 5.1.16-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.r4/pom.xml b/org.hl7.fhir.r4/pom.xml index d8b4d619c..d1b6c2663 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 - 5.1.15 + 5.1.16-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.r5/pom.xml b/org.hl7.fhir.r5/pom.xml index 242bcf844..bf27f4d2e 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 - 5.1.15 + 5.1.16-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.report/pom.xml b/org.hl7.fhir.report/pom.xml index c1d9c4d64..1573279dc 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 - 5.1.15 + 5.1.16-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.utilities/pom.xml b/org.hl7.fhir.utilities/pom.xml index ba3a019d9..8072b4156 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 - 5.1.15 + 5.1.16-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.validation.cli/pom.xml b/org.hl7.fhir.validation.cli/pom.xml index c68842aaa..e1ec66572 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 - 5.1.15 + 5.1.16-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.validation/pom.xml b/org.hl7.fhir.validation/pom.xml index 10a9c28d4..ee22814c6 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 - 5.1.15 + 5.1.16-SNAPSHOT ../pom.xml diff --git a/pom.xml b/pom.xml index d076236ed..5829bbfe7 100644 --- a/pom.xml +++ b/pom.xml @@ -14,7 +14,7 @@ HAPI FHIR. --> org.hl7.fhir.core - 5.1.15 + 5.1.16-SNAPSHOT pom From 2d4664498259993d25e5f9292c75c19e7e721e7a Mon Sep 17 00:00:00 2001 From: Mark Iantorno Date: Mon, 28 Sep 2020 09:28:29 -0400 Subject: [PATCH 59/73] Labelling update for pipelines ***NO_CI*** --- master-branch-pipeline.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/master-branch-pipeline.yml b/master-branch-pipeline.yml index 3708aba4b..475fffa5b 100644 --- a/master-branch-pipeline.yml +++ b/master-branch-pipeline.yml @@ -77,7 +77,7 @@ steps: # Deploy the SNAPSHOT artifact to sonatype nexus. # This is done for the master branch merges only. - task: Maven@3 - displayName: 'Deploy $(module) to Sonatype staging' + displayName: 'Deploy to Sonatype staging' inputs: mavenPomFile: '$(System.DefaultWorkingDirectory)/pom.xml' goals: deploy @@ -87,7 +87,7 @@ steps: # Deploy the SNAPSHOT artifact to GitHub packages. # This is done for the master branch merges only. - task: Maven@3 - displayName: 'Deploy $(module) to Sonatype staging' + displayName: 'Deploy to GitHub packages' inputs: mavenPomFile: '$(System.DefaultWorkingDirectory)/pom.xml' goals: deploy From 510344aa1b35ef9ca19f60c2d7fdd73bd098babf Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Wed, 30 Sep 2020 09:22:16 +1000 Subject: [PATCH 60/73] Fix FHIRPath engine for updated tests for date addition/subtraction --- .../org/hl7/fhir/r4/utils/FHIRPathEngine.java | 76 ++++++++++++++++++- .../org/hl7/fhir/r4/test/FHIRPathTests.java | 2 +- .../org/hl7/fhir/r5/utils/FHIRPathEngine.java | 74 +++++++++++++++++- .../org/hl7/fhir/r5/test/FHIRPathTests.java | 6 +- 4 files changed, 150 insertions(+), 8 deletions(-) diff --git a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/FHIRPathEngine.java b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/FHIRPathEngine.java index aedd55871..89f805006 100644 --- a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/FHIRPathEngine.java +++ b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/FHIRPathEngine.java @@ -1514,6 +1514,13 @@ public class FHIRPathEngine { result.addType(TypeDetails.FP_Decimal); else if (left.hasType(worker, "string", "id", "code", "uri") && right.hasType(worker, "string", "id", "code", "uri")) result.addType(TypeDetails.FP_String); + else if (left.hasType(worker, "date", "dateTime", "instant")) { + if (right.hasType(worker, "Quantity")) { + result.addType(left.getType()); + } else { + throw new PathEngineException(String.format("Error in date arithmetic: Unable to add type {0} to {1}", right.getType(), left.getType())); + } + } return result; case Minus: result = new TypeDetails(CollectionStatus.SINGLETON); @@ -1521,6 +1528,13 @@ public class FHIRPathEngine { result.addType(TypeDetails.FP_Integer); else if (left.hasType(worker, "integer", "decimal") && right.hasType(worker, "integer", "decimal")) result.addType(TypeDetails.FP_Decimal); + else if (left.hasType(worker, "date", "dateTime", "instant")) { + if (right.hasType(worker, "Quantity")) { + result.addType(left.getType()); + } else { + throw new PathEngineException(String.format("Error in date arithmetic: Unable to subtract type {0} from {1}", right.getType(), left.getType())); + } + } return result; case Div: case Mod: @@ -1965,7 +1979,7 @@ public class FHIRPathEngine { throw new PathEngineException(String.format("Error performing +: left operand has the wrong type (%s)", left.get(0).fhirType())); if (right.size() > 1) throw new PathEngineException("Error performing +: right operand has more than one value"); - if (!right.get(0).isPrimitive()) + if (!right.get(0).isPrimitive() && !((left.get(0).isDateTime() || "0".equals(left.get(0).primitiveValue()) || left.get(0).hasType("Quantity")) && right.get(0).hasType("Quantity"))) throw new PathEngineException(String.format("Error performing +: right operand has the wrong type (%s)", right.get(0).fhirType())); List result = new ArrayList(); @@ -1977,11 +1991,67 @@ public class FHIRPathEngine { result.add(new IntegerType(Integer.parseInt(l.primitiveValue()) + Integer.parseInt(r.primitiveValue()))); else if (l.hasType("decimal", "integer") && r.hasType("decimal", "integer")) result.add(new DecimalType(new BigDecimal(l.primitiveValue()).add(new BigDecimal(r.primitiveValue())))); + else if (l.isDateTime() && r.hasType("Quantity")) + result.add(dateAdd((BaseDateTimeType) l, (Quantity) r, false)); else throw new PathEngineException(String.format("Error performing +: left and right operand have incompatible or illegal types (%s, %s)", left.get(0).fhirType(), right.get(0).fhirType())); return result; } + private BaseDateTimeType dateAdd(BaseDateTimeType d, Quantity q, boolean negate) { + BaseDateTimeType result = (BaseDateTimeType) d.copy(); + + int value = negate ? 0 - q.getValue().intValue() : q.getValue().intValue(); + switch (q.hasCode() ? q.getCode() : q.getUnit()) { + case "years": + case "year": + result.add(Calendar.YEAR, value); + break; + case "a": + throw new PathEngineException(String.format("Error in date arithmetic: attempt to add a definite quantity duration time unit %s", q.getCode())); + case "months": + case "month": + result.add(Calendar.MONTH, value); + break; + case "mo": + throw new PathEngineException(String.format("Error in date arithmetic: attempt to add a definite quantity duration time unit %s", q.getCode())); + case "weeks": + case "week": + case "wk": + result.add(Calendar.DAY_OF_MONTH, value * 7); + break; + case "days": + case "day": + case "d": + result.add(Calendar.DAY_OF_MONTH, value); + break; + case "hours": + case "hour": + case "h": + result.add(Calendar.HOUR, value); + break; + case "minutes": + case "minute": + case "min": + result.add(Calendar.MINUTE, value); + break; + case "seconds": + case "second": + case "s": + result.add(Calendar.SECOND, value); + break; + case "milliseconds": + case "millisecond": + case "ms": + result.add(Calendar.MILLISECOND, value); + break; + default: + throw new PathEngineException(String.format("Error in date arithmetic: unrecognized time unit %s", q.getCode())); + } + return result; + } + + private List opTimes(List left, List right) throws PathEngineException { if (left.size() == 0 || right.size() == 0) return new ArrayList(); @@ -2148,7 +2218,7 @@ public class FHIRPathEngine { throw new PathEngineException(String.format("Error performing -: left operand has the wrong type (%s)", left.get(0).fhirType())); if (right.size() > 1) throw new PathEngineException("Error performing -: right operand has more than one value"); - if (!right.get(0).isPrimitive()) + if (!right.get(0).isPrimitive() && !((left.get(0).isDateTime() || "0".equals(left.get(0).primitiveValue()) || left.get(0).hasType("Quantity")) && right.get(0).hasType("Quantity"))) throw new PathEngineException(String.format("Error performing -: right operand has the wrong type (%s)", right.get(0).fhirType())); List result = new ArrayList(); @@ -2159,6 +2229,8 @@ public class FHIRPathEngine { result.add(new IntegerType(Integer.parseInt(l.primitiveValue()) - Integer.parseInt(r.primitiveValue()))); else if (l.hasType("decimal", "integer") && r.hasType("decimal", "integer")) result.add(new DecimalType(new BigDecimal(l.primitiveValue()).subtract(new BigDecimal(r.primitiveValue())))); + else if (l.isDateTime() && r.hasType("Quantity")) + result.add(dateAdd((BaseDateTimeType) l, (Quantity) r, true)); else throw new PathEngineException(String.format("Error performing -: left and right operand have incompatible or illegal types (%s, %s)", left.get(0).fhirType(), right.get(0).fhirType())); return result; diff --git a/org.hl7.fhir.r4/src/test/java/org/hl7/fhir/r4/test/FHIRPathTests.java b/org.hl7.fhir.r4/src/test/java/org/hl7/fhir/r4/test/FHIRPathTests.java index 0b7f7b0f2..79ea4fcb0 100644 --- a/org.hl7.fhir.r4/src/test/java/org/hl7/fhir/r4/test/FHIRPathTests.java +++ b/org.hl7.fhir.r4/src/test/java/org/hl7/fhir/r4/test/FHIRPathTests.java @@ -205,7 +205,7 @@ public class FHIRPathTests { Assertions.assertTrue(outcome.get(i).equalsDeep(q), String.format("Outcome %d: Value should be %s but was %s", i, v, outcome.get(i).toString())); } else { Assertions.assertTrue(outcome.get(i) instanceof PrimitiveType, String.format("Outcome %d: Value should be a primitive type but was %s", i, outcome.get(i).fhirType())); - Assertions.assertEquals(v, ((PrimitiveType) outcome.get(i)).asStringValue(), String.format("Outcome %d: Value should be %s but was %s for expression %s", i, v, outcome.get(i).toString(), expression)); + Assertions.assertEquals(v, ((PrimitiveType) outcome.get(i)).fpValue(), String.format("Outcome %d: Value should be %s but was %s for expression %s", i, v, ((PrimitiveType) outcome.get(i)).fpValue(), expression)); } } } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java index 5b6c553ff..6f6e4de68 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java @@ -5,6 +5,7 @@ import java.math.RoundingMode; import java.rmi.server.LoaderHandler; import java.util.ArrayList; import java.util.Base64; +import java.util.Calendar; import java.util.Date; import java.util.EnumSet; import java.util.HashMap; @@ -1771,6 +1772,12 @@ public class FHIRPathEngine { result.addType(TypeDetails.FP_Decimal); } else if (left.hasType(worker, "string", "id", "code", "uri") && right.hasType(worker, "string", "id", "code", "uri")) { result.addType(TypeDetails.FP_String); + } else if (left.hasType(worker, "date", "dateTime", "instant")) { + if (right.hasType(worker, "Quantity")) { + result.addType(left.getType()); + } else { + throw new PathEngineException(String.format("Error in date arithmetic: Unable to add type {0} to {1}", right.getType(), left.getType())); + } } return result; case Minus: @@ -1781,6 +1788,12 @@ public class FHIRPathEngine { result.addType(TypeDetails.FP_Decimal); } else if (left.hasType(worker, "Quantity") && right.hasType(worker, "Quantity")) { result.addType(TypeDetails.FP_Quantity); + } else if (left.hasType(worker, "date", "dateTime", "instant")) { + if (right.hasType(worker, "Quantity")) { + result.addType(left.getType()); + } else { + throw new PathEngineException(String.format("Error in date arithmetic: Unable to subtract type {0} from {1}", right.getType(), left.getType())); + } } return result; case Div: @@ -2385,7 +2398,7 @@ public class FHIRPathEngine { if (right.size() > 1) { throw makeException(I18nConstants.FHIRPATH_RIGHT_VALUE_PLURAL, "+"); } - if (!right.get(0).isPrimitive()) { + if (!right.get(0).isPrimitive() && !((left.get(0).isDateTime() || "0".equals(left.get(0).primitiveValue()) || left.get(0).hasType("Quantity")) && right.get(0).hasType("Quantity"))) { throw makeException(I18nConstants.FHIRPATH_RIGHT_VALUE_WRONG_TYPE, "+", right.get(0).fhirType()); } @@ -2398,12 +2411,67 @@ public class FHIRPathEngine { result.add(new IntegerType(Integer.parseInt(l.primitiveValue()) + Integer.parseInt(r.primitiveValue()))); } else if (l.hasType("decimal", "integer") && r.hasType("decimal", "integer")) { result.add(new DecimalType(new BigDecimal(l.primitiveValue()).add(new BigDecimal(r.primitiveValue())))); + } else if (l.isDateTime() && r.hasType("Quantity")) { + result.add(dateAdd((BaseDateTimeType) l, (Quantity) r, false)); } else { throw makeException(I18nConstants.FHIRPATH_OP_INCOMPATIBLE, "+", left.get(0).fhirType(), right.get(0).fhirType()); } return result; } + private BaseDateTimeType dateAdd(BaseDateTimeType d, Quantity q, boolean negate) { + BaseDateTimeType result = (BaseDateTimeType) d.copy(); + + int value = negate ? 0 - q.getValue().intValue() : q.getValue().intValue(); + switch (q.hasCode() ? q.getCode() : q.getUnit()) { + case "years": + case "year": + result.add(Calendar.YEAR, value); + break; + case "a": + throw new PathEngineException(String.format("Error in date arithmetic: attempt to add a definite quantity duration time unit %s", q.getCode())); + case "months": + case "month": + result.add(Calendar.MONTH, value); + break; + case "mo": + throw new PathEngineException(String.format("Error in date arithmetic: attempt to add a definite quantity duration time unit %s", q.getCode())); + case "weeks": + case "week": + case "wk": + result.add(Calendar.DAY_OF_MONTH, value * 7); + break; + case "days": + case "day": + case "d": + result.add(Calendar.DAY_OF_MONTH, value); + break; + case "hours": + case "hour": + case "h": + result.add(Calendar.HOUR, value); + break; + case "minutes": + case "minute": + case "min": + result.add(Calendar.MINUTE, value); + break; + case "seconds": + case "second": + case "s": + result.add(Calendar.SECOND, value); + break; + case "milliseconds": + case "millisecond": + case "ms": + result.add(Calendar.MILLISECOND, value); + break; + default: + throw new PathEngineException(String.format("Error in date arithmetic: unrecognized time unit %s", q.getCode())); + } + return result; + } + private List opTimes(List left, List right) throws PathEngineException { if (left.size() == 0 || right.size() == 0) { return new ArrayList(); @@ -2589,7 +2657,7 @@ public class FHIRPathEngine { if (right.size() > 1) { throw makeException(I18nConstants.FHIRPATH_RIGHT_VALUE_PLURAL, "-"); } - if (!right.get(0).isPrimitive() && !right.get(0).hasType("Quantity")) { + if (!right.get(0).isPrimitive() && !((left.get(0).isDateTime() || "0".equals(left.get(0).primitiveValue()) || left.get(0).hasType("Quantity")) && right.get(0).hasType("Quantity"))) { throw makeException(I18nConstants.FHIRPATH_RIGHT_VALUE_WRONG_TYPE, "-", right.get(0).fhirType()); } @@ -2607,6 +2675,8 @@ public class FHIRPathEngine { Quantity qty = (Quantity) r; result.add(qty.copy().setValue(qty.getValue().abs())); } + } else if (l.isDateTime() && r.hasType("Quantity")) { + result.add(dateAdd((BaseDateTimeType) l, (Quantity) r, true)); } else { throw makeException(I18nConstants.FHIRPATH_OP_INCOMPATIBLE, "-", left.get(0).fhirType(), right.get(0).fhirType()); } diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/FHIRPathTests.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/FHIRPathTests.java index 108ea465a..322027805 100644 --- a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/FHIRPathTests.java +++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/FHIRPathTests.java @@ -254,11 +254,11 @@ public class FHIRPathTests { Assertions.assertTrue(outcome.get(i).equalsDeep(q), String.format("Outcome %d: Value should be %s but was %s", i, v, outcome.get(i).toString())); } else { Assertions.assertTrue(outcome.get(i) instanceof PrimitiveType, String.format("Outcome %d: Value should be a primitive type but was %s", i, outcome.get(i).fhirType())); - if (!(v.equals(((PrimitiveType) outcome.get(i)).asStringValue()))) { + if (!(v.equals(((PrimitiveType) outcome.get(i)).fpValue()))) { System.out.println(name); - System.out.println(String.format("Outcome %d: Value should be %s but was %s for expression %s", i, v, outcome.get(i).toString(), expression)); + System.out.println(String.format("Outcome %d: Value should be %s but was %s for expression %s", i, v, ((PrimitiveType) outcome.get(i)).fpValue(), expression)); } - Assertions.assertEquals(v, ((PrimitiveType) outcome.get(i)).asStringValue(), String.format("Outcome %d: Value should be %s but was %s for expression %s", i, v, outcome.get(i).toString(), expression)); + Assertions.assertEquals(v, ((PrimitiveType) outcome.get(i)).fpValue(), String.format("Outcome %d: Value should be %s but was %s for expression %s", i, v, ((PrimitiveType) outcome.get(i)).fpValue(), expression)); } } } From bcb2d8e1487edd947af5e43b5d19bc17da985bd9 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Wed, 30 Sep 2020 09:23:54 +1000 Subject: [PATCH 61/73] fix questionnaire mode support for validator --- .../src/main/resources/Messages.properties | 12 +++---- .../hl7/fhir/validation/ValidationEngine.java | 35 ++++++++++++++----- .../org/hl7/fhir/validation/Validator.java | 2 ++ .../fhir/validation/cli/model/CliContext.java | 29 ++++++--------- .../services/StandAloneValidatorFetcher.java | 6 ++-- .../cli/services/ValidationService.java | 2 +- .../fhir/validation/cli/utils/Display.java | 4 +-- .../hl7/fhir/validation/cli/utils/Params.java | 6 ++-- .../instance/InstanceValidator.java | 14 ++++++-- .../instance/type/QuestionnaireValidator.java | 18 ++++++++-- 10 files changed, 82 insertions(+), 46 deletions(-) diff --git a/org.hl7.fhir.utilities/src/main/resources/Messages.properties b/org.hl7.fhir.utilities/src/main/resources/Messages.properties index 18bee95a6..f9d145fbf 100644 --- a/org.hl7.fhir.utilities/src/main/resources/Messages.properties +++ b/org.hl7.fhir.utilities/src/main/resources/Messages.properties @@ -133,11 +133,11 @@ Terminology_TX_Code_ValueSetMax = No code provided, and a code must be provided Terminology_TX_Code_ValueSet_Ext = No code provided, and a code should be provided from the value set {0} ({1}) Terminology_TX_Coding_Count = Expected {0} but found {1} coding elements Terminology_TX_Confirm_1 = Could not confirm that the codes provided are in the value set {0} and a code from this value set is required (class = {1}) -Terminology_TX_Confirm_2 = Could not confirm that the codes provided are in the value set {0} and a code should come from this value set unless it has no suitable code (class = {1}) +Terminology_TX_Confirm_2 = Could not confirm that the codes provided are in the value set {0} and a code should come from this value set unless it has no suitable code (the validator cannot judge what is suitable) (class = {1}) Terminology_TX_Confirm_3 = Could not confirm that the codes provided are in the value set {0} and a code is recommended to come from this value set (class = {1}) Terminology_TX_Confirm_4a = The code provided ({2}) is not in the value set {0}, and a code from this value set is required: {1} Terminology_TX_Confirm_4b = The codes provided ({2}) are not in the value set {0}, and a code from this value set is required: {1} -Terminology_TX_Confirm_5 = Could not confirm that the codes provided are in the value set {0}, and a code should come from this value set unless it has no suitable code +Terminology_TX_Confirm_5 = Could not confirm that the codes provided are in the value set {0}, and a code should come from this value set unless it has no suitable code (the validator cannot judge what is suitable) Terminology_TX_Confirm_6 = Could not confirm that the codes provided are in the value set {0}, and a code is recommended to come from this value set Terminology_TX_Display_Wrong = Display should be ''{0}'' Terminology_TX_Error_CodeableConcept = Error {0} validating CodeableConcept @@ -148,16 +148,16 @@ Terminology_TX_NoValid_1 = None of the codes provided are in the value set {0} ( Terminology_TX_NoValid_10 = The code provided is not in the maximum value set {0} ({1}), and a code from this value set is required) (code = {2}#{3}) Terminology_TX_NoValid_11 = The code provided is not in the maximum value set {0} ({1}{2}) Terminology_TX_NoValid_12 = The Coding provided ({2}) is not in the value set {0}, and a code is required from this value set. {1} -Terminology_TX_NoValid_13 = The Coding provided ({2}) is not in the value set {0}, and a code should come from this value set unless it has no suitable code. {1} +Terminology_TX_NoValid_13 = The Coding provided ({2}) is not in the value set {0}, and a code should come from this value set unless it has no suitable code (the validator cannot judge what is suitable). {1} Terminology_TX_NoValid_14 = The Coding provided ({2}) is not in the value set {0}, and a code is recommended to come from this value set. {1} Terminology_TX_NoValid_15 = The value provided (''{0}'') could not be validated in the absence of a terminology server Terminology_TX_NoValid_16 = The value provided (''{0}'') is not in the value set {1} ({2}), and a code is required from this value set){3} -Terminology_TX_NoValid_17 = The value provided (''{0}'') is not in the value set {1} ({2}), and a code should come from this value set unless it has no suitable code){3} +Terminology_TX_NoValid_17 = The value provided (''{0}'') is not in the value set {1} ({2}), and a code should come from this value set unless it has no suitable code and the validator cannot judge what is suitable){3} Terminology_TX_NoValid_18 = The value provided (''{0}'') is not in the value set {1} ({2}), and a code is recommended to come from this value set){3} -Terminology_TX_NoValid_2 = None of the codes provided are in the value set {0} ({1}), and a code should come from this value set unless it has no suitable code) (codes = {2}) +Terminology_TX_NoValid_2 = None of the codes provided are in the value set {0} ({1}), and a code should come from this value set unless it has no suitable code and the validator cannot judge what is suitable) (codes = {2}) Terminology_TX_NoValid_3 = None of the codes provided are in the value set {0} ({1}), and a code is recommended to come from this value set) (codes = {2}) Terminology_TX_NoValid_4 = The Coding provided ({2}) is not in the value set {0}, and a code is required from this value set {1} -Terminology_TX_NoValid_5 = The Coding provided ({2}) is not in the value set {0}, and a code should come from this value set unless it has no suitable code {1} +Terminology_TX_NoValid_5 = The Coding provided ({2}) is not in the value set {0}, and a code should come from this value set unless it has no suitable code (the validator cannot judge what is suitable) {1} Terminology_TX_NoValid_6 = The Coding provided ({2}) is not in the value set {0}, and a code is recommended to come from this value set {1} Terminology_TX_NoValid_7 = None of the codes provided could be validated against the maximum value set {0} ({1}), (error = {2}) Terminology_TX_NoValid_8 = None of the codes provided are in the maximum value set {0} ({1}), and a code from this value set is required) (codes = {2}) 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 3a21f7591..506c54680 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 @@ -34,7 +34,13 @@ import org.hl7.fhir.r5.utils.*; import org.hl7.fhir.r5.utils.IResourceValidator.*; import org.hl7.fhir.r5.utils.StructureMapUtilities.ITransformerServices; import org.hl7.fhir.utilities.i18n.I18nConstants; +import org.hl7.fhir.utilities.npm.BasePackageCacheManager; +import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; +import org.hl7.fhir.utilities.npm.NpmPackage; +import org.hl7.fhir.utilities.npm.PackageClient; +import org.hl7.fhir.utilities.npm.ToolsVersion; import org.hl7.fhir.validation.BaseValidator.ValidationControl; +import org.hl7.fhir.validation.Validator.QuestionnaireMode; import org.hl7.fhir.validation.cli.services.StandAloneValidatorFetcher.IPackageInstaller; import org.hl7.fhir.validation.instance.InstanceValidator; import org.hl7.fhir.utilities.IniFile; @@ -42,11 +48,6 @@ import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.TimeTracker; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.VersionUtilities; -import org.hl7.fhir.utilities.cache.NpmPackage; -import org.hl7.fhir.utilities.cache.PackageClient; -import org.hl7.fhir.utilities.cache.BasePackageCacheManager; -import org.hl7.fhir.utilities.cache.FilesystemPackageCacheManager; -import org.hl7.fhir.utilities.cache.ToolsVersion; import org.hl7.fhir.utilities.i18n.I18nBase; import org.hl7.fhir.utilities.i18n.I18nConstants; import org.hl7.fhir.utilities.validation.ValidationMessage; @@ -311,6 +312,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst private boolean showTimes; private List bundleValidationRules = new ArrayList<>(); private Map validationControl = new HashMap<>(); + private QuestionnaireMode questionnaireMode; private class AsteriskFilter implements FilenameFilter { String dir; @@ -531,7 +533,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst v = src.substring(src.indexOf("|")+1); src = src.substring(0, src.indexOf("|")); } - String pid = pcm.getPackageId(src); + String pid = explore ? pcm.getPackageId(src) : null; if (!Utilities.noString(pid)) return fetchByPackage(pid+(v == null ? "" : "#"+v)); else @@ -563,7 +565,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst } else if ((src.matches(FilesystemPackageCacheManager.PACKAGE_REGEX) || src.matches(FilesystemPackageCacheManager.PACKAGE_VERSION_REGEX)) && !src.endsWith(".zip") && !src.endsWith(".tgz")) { return fetchByPackage(src); } - throw new FHIRException("Unable to find/resolve/read -ig "+src); + throw new FHIRException("Unable to find/resolve/read "+(explore ? "-ig " : "")+src); } private Map loadIgSourceForVersion(String src, boolean recursive, boolean explore, VersionSourceInformation versions) throws FHIRException, IOException { @@ -705,7 +707,20 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst res.put(Utilities.changeFileExt(src, "."+fmt.getExtension()), cnt); return res; } - throw new FHIRException("Unable to find/resolve/read -ig "+src); + String fn = Utilities.path("[tmp]", "fetch-resource-error-content.bin"); + TextFile.bytesToFile(cnt, fn); + System.out.println("Error Fetching "+src); + System.out.println("Some content was found, saved to "+fn); + System.out.println("1st 100 bytes = "+presentForDebugging(cnt)); + throw new FHIRException("Unable to find/resolve/read "+(explore ? "-ig " : "")+src); + } + + private String presentForDebugging(byte[] cnt) { + StringBuilder b = new StringBuilder(); + for (int i = 0; i < Integer.min(cnt.length, 50); i++) { + b.append(Integer.toHexString(cnt[i])); + } + return b.toString(); } private InputStream fetchFromUrlSpecific(String source, boolean optional) throws FHIRException, IOException { @@ -1142,7 +1157,8 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst } } - public void setQuestionnaires(List questionnaires) { + public void setQuestionnaireMode(Validator.QuestionnaireMode questionnaireMode) { + this.questionnaireMode = questionnaireMode; } public void setNative(boolean doNative) { @@ -1614,6 +1630,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst validator.getImplementationGuides().addAll(igs); validator.getBundleValidationRules().addAll(bundleValidationRules); validator.getValidationControl().putAll(validationControl ); + validator.setQuestionnaireMode(questionnaireMode); return validator; } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/Validator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/Validator.java index 8b6a38bf3..be1da42f0 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/Validator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/Validator.java @@ -91,6 +91,8 @@ public class Validator { public enum EngineMode { VALIDATION, TRANSFORM, NARRATIVE, SNAPSHOT, SCAN, CONVERT, FHIRPATH, VERSION } + + public enum QuestionnaireMode { NONE, CHECK, REQUIRED } private static CliContext cliContext; 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 1ed9893a9..eea13ac6c 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 @@ -54,8 +54,9 @@ public class CliContext { @JsonProperty("igs") private List igs = new ArrayList(); - @JsonProperty("questionnaires") - private List questionnaires = new ArrayList(); + @JsonProperty("questionnaire") + private Validator.QuestionnaireMode questionnaireMode = Validator.QuestionnaireMode.CHECK; + @JsonProperty("profiles") private List profiles = new ArrayList(); @JsonProperty("sources") @@ -118,22 +119,14 @@ public class CliContext { return this; } - @JsonProperty("questionnaires") - public List getQuestionnaires() { - return questionnaires; + @JsonProperty("questionnaire") + public Validator.QuestionnaireMode getQuestionnaireMode() { + return questionnaireMode; } - @JsonProperty("questionnaires") - public CliContext setQuestionnaires(List questionnaires) { - this.questionnaires = questionnaires; - return this; - } - - public CliContext addQuestionnaire(String questionnaire) { - if (this.questionnaires == null) { - this.questionnaires = new ArrayList<>(); - } - this.questionnaires.add(questionnaire); + @JsonProperty("questionnaire") + public CliContext setQuestionnaireMode(Validator.QuestionnaireMode questionnaireMode) { + this.questionnaireMode = questionnaireMode; return this; } @@ -482,7 +475,7 @@ public class CliContext { Objects.equals(snomedCT, that.snomedCT) && Objects.equals(targetVer, that.targetVer) && Objects.equals(igs, that.igs) && - Objects.equals(questionnaires, that.questionnaires) && + Objects.equals(questionnaireMode, that.questionnaireMode) && Objects.equals(profiles, that.profiles) && Objects.equals(sources, that.sources) && Objects.equals(crumbTrails, that.crumbTrails) && @@ -494,6 +487,6 @@ public class CliContext { @Override public int hashCode() { - return Objects.hash(doNative, anyExtensionsAllowed, hintAboutNonMustSupport, recursive, doDebug, assumeValidRestReferences, canDoNative, noInternalCaching, noExtensibleBindingMessages, map, output, txServer, sv, txLog, mapLog, lang, fhirpath, snomedCT, targetVer, igs, questionnaires, profiles, sources, mode, locale, locations, crumbTrails, showTimes); + return Objects.hash(doNative, anyExtensionsAllowed, hintAboutNonMustSupport, recursive, doDebug, assumeValidRestReferences, canDoNative, noInternalCaching, noExtensibleBindingMessages, map, output, txServer, sv, txLog, mapLog, lang, fhirpath, snomedCT, targetVer, igs, questionnaireMode, profiles, sources, mode, locale, locations, crumbTrails, showTimes); } } \ No newline at end of file diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/services/StandAloneValidatorFetcher.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/services/StandAloneValidatorFetcher.java index 9626987e7..0dd0b3412 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/services/StandAloneValidatorFetcher.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/services/StandAloneValidatorFetcher.java @@ -14,9 +14,9 @@ import org.hl7.fhir.r5.utils.IResourceValidator.ReferenceValidationPolicy; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.VersionUtilities; import org.hl7.fhir.utilities.VersionUtilities.VersionURLInfo; -import org.hl7.fhir.utilities.cache.BasePackageCacheManager; -import org.hl7.fhir.utilities.cache.FilesystemPackageCacheManager; -import org.hl7.fhir.utilities.cache.NpmPackage; +import org.hl7.fhir.utilities.npm.BasePackageCacheManager; +import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; +import org.hl7.fhir.utilities.npm.NpmPackage; import org.hl7.fhir.validation.cli.services.StandAloneValidatorFetcher.IPackageInstaller; public class StandAloneValidatorFetcher implements IValidatorResourceFetcher { 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 5ec8f9b56..0b8580e40 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 @@ -203,7 +203,7 @@ public class ValidationService { validator.loadIg(src, cliContext.isRecursive()); } System.out.print(" Get set... "); - validator.setQuestionnaires(cliContext.getQuestionnaires()); + validator.setQuestionnaireMode(cliContext.getQuestionnaireMode()); validator.setNative(cliContext.isDoNative()); validator.setHintAboutNonMustSupport(cliContext.isHintAboutNonMustSupport()); validator.setAnyExtensionsAllowed(cliContext.isAnyExtensionsAllowed()); diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/utils/Display.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/utils/Display.java index a57040513..09397e776 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/utils/Display.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/utils/Display.java @@ -2,8 +2,8 @@ package org.hl7.fhir.validation.cli.utils; import org.hl7.fhir.r5.model.Constants; import org.hl7.fhir.utilities.VersionUtilities; -import org.hl7.fhir.utilities.cache.FilesystemPackageCacheManager; -import org.hl7.fhir.utilities.cache.ToolsVersion; +import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; +import org.hl7.fhir.utilities.npm.ToolsVersion; import java.io.IOException; 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 68638cdfc..20211de73 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 @@ -122,8 +122,10 @@ public class Params { } else if (args[i].equals(QUESTIONNAIRE)) { if (i + 1 == args.length) throw new Error("Specified -questionnaire without indicating questionnaire file"); - else - cliContext.addQuestionnaire(args[++i]); + else { + String q = args[++i]; + cliContext.setQuestionnaireMode(Validator.QuestionnaireMode.valueOf(q)); + } } else if (args[i].equals(NATIVE)) { cliContext.setDoNative(true); } else if (args[i].equals(ASSUME_VALID_REST_REF)) { 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 0c7ab8330..4794d133a 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 @@ -140,6 +140,7 @@ import org.hl7.fhir.r5.utils.ToolingExtensions; import org.hl7.fhir.r5.utils.XVerExtensionManager; import org.hl7.fhir.utilities.i18n.I18nConstants; import org.hl7.fhir.validation.BaseValidator; +import org.hl7.fhir.validation.Validator.QuestionnaireMode; import org.hl7.fhir.validation.instance.type.BundleValidator; import org.hl7.fhir.validation.instance.type.CodeSystemValidator; import org.hl7.fhir.validation.instance.type.MeasureValidator; @@ -375,6 +376,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat private boolean crumbTrails; private List bundleValidationRules = new ArrayList<>(); private boolean validateValueSetCodesOnTxServer = true; + private QuestionnaireMode questionnaireMode; public InstanceValidator(IWorkerContext theContext, IEvaluationContext hostServices) { super(theContext); @@ -3844,9 +3846,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } else if (element.getType().equals("Observation")) { validateObservation(errors, element, stack); } else if (element.getType().equals("Questionnaire")) { - new QuestionnaireValidator(context, myEnableWhenEvaluator, fpe, timeTracker).validateQuestionannaire(errors, element, element, stack); + new QuestionnaireValidator(context, myEnableWhenEvaluator, fpe, timeTracker, questionnaireMode).validateQuestionannaire(errors, element, element, stack); } else if (element.getType().equals("QuestionnaireResponse")) { - new QuestionnaireValidator(context, myEnableWhenEvaluator, fpe, timeTracker).validateQuestionannaireResponse(hostContext, errors, element, stack); + new QuestionnaireValidator(context, myEnableWhenEvaluator, fpe, timeTracker, questionnaireMode).validateQuestionannaireResponse(hostContext, errors, element, stack); } else if (element.getType().equals("Measure")) { new MeasureValidator(context, timeTracker).validateMeasure(hostContext, errors, element, stack); } else if (element.getType().equals("MeasureReport")) { @@ -5081,4 +5083,12 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } + public void setQuestionnaireMode(QuestionnaireMode questionnaireMode) { + this.questionnaireMode = questionnaireMode; + } + + public QuestionnaireMode getQuestionnaireMode() { + return questionnaireMode; + } + } \ No newline at end of file diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/QuestionnaireValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/QuestionnaireValidator.java index 492a689af..d37ffa2a1 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/QuestionnaireValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/QuestionnaireValidator.java @@ -45,6 +45,7 @@ import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType; import org.hl7.fhir.utilities.validation.ValidationMessage.Source; import org.hl7.fhir.validation.BaseValidator; import org.hl7.fhir.validation.TimeTracker; +import org.hl7.fhir.validation.Validator.QuestionnaireMode; import org.hl7.fhir.validation.instance.EnableWhenEvaluator; import org.hl7.fhir.validation.instance.EnableWhenEvaluator.QStack; import org.hl7.fhir.validation.instance.utils.NodeStack; @@ -56,13 +57,15 @@ public class QuestionnaireValidator extends BaseValidator { private EnableWhenEvaluator myEnableWhenEvaluator; private FHIRPathEngine fpe; + private QuestionnaireMode questionnaireMode; - public QuestionnaireValidator(IWorkerContext context, EnableWhenEvaluator myEnableWhenEvaluator, FHIRPathEngine fpe, TimeTracker timeTracker) { + public QuestionnaireValidator(IWorkerContext context, EnableWhenEvaluator myEnableWhenEvaluator, FHIRPathEngine fpe, TimeTracker timeTracker, QuestionnaireMode questionnaireMode) { super(context); source = Source.InstanceValidator; this.myEnableWhenEvaluator = myEnableWhenEvaluator; this.fpe = fpe; this.timeTracker = timeTracker; + this.questionnaireMode = questionnaireMode; } public void validateQuestionannaire(List errors, Element element, Element element2, NodeStack stack) { @@ -164,6 +167,9 @@ public class QuestionnaireValidator extends BaseValidator { } public void validateQuestionannaireResponse(ValidatorHostContext hostContext, List errors, Element element, NodeStack stack) throws FHIRException { + if (questionnaireMode == QuestionnaireMode.NONE) { + return; + } Element q = element.getNamedChild("questionnaire"); String questionnaire = null; if (q != null) { @@ -179,9 +185,15 @@ public class QuestionnaireValidator extends BaseValidator { questionnaire = q.getChildValue("reference"); } } - if (hint(errors, IssueType.REQUIRED, element.line(), element.col(), stack.getLiteralPath(), questionnaire != null, I18nConstants.QUESTIONNAIRE_QR_Q_NONE)) { + boolean ok = questionnaireMode == QuestionnaireMode.REQUIRED ? + rule(errors, IssueType.REQUIRED, element.line(), element.col(), stack.getLiteralPath(), questionnaire != null, I18nConstants.QUESTIONNAIRE_QR_Q_NONE) : + hint(errors, IssueType.REQUIRED, element.line(), element.col(), stack.getLiteralPath(), questionnaire != null, I18nConstants.QUESTIONNAIRE_QR_Q_NONE); + if (ok) { Questionnaire qsrc = questionnaire.startsWith("#") ? loadQuestionnaire(element, questionnaire.substring(1)) : context.fetchResource(Questionnaire.class, questionnaire); - if (warning(errors, IssueType.REQUIRED, q.line(), q.col(), stack.getLiteralPath(), qsrc != null, I18nConstants.QUESTIONNAIRE_QR_Q_NOTFOUND, questionnaire)) { + ok = questionnaireMode == QuestionnaireMode.REQUIRED ? + rule(errors, IssueType.REQUIRED, q.line(), q.col(), stack.getLiteralPath(), qsrc != null, I18nConstants.QUESTIONNAIRE_QR_Q_NOTFOUND, questionnaire) : + warning(errors, IssueType.REQUIRED, q.line(), q.col(), stack.getLiteralPath(), qsrc != null, I18nConstants.QUESTIONNAIRE_QR_Q_NOTFOUND, questionnaire); + if (ok) { boolean inProgress = "in-progress".equals(element.getNamedChildValue("status")); validateQuestionannaireResponseItems(hostContext, qsrc, qsrc.getItem(), errors, element, stack, inProgress, element, new QStack(qsrc, element)); } From 5be73ff9c55c5469b923a0a5b3b221d7e3962b48 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Wed, 30 Sep 2020 09:24:26 +1000 Subject: [PATCH 62/73] rename org.hl7.fhir.utilities.cache to org.hl7.fhir.utilities.npm --- .../ExtensionDefinitionGenerator.java | 8 +- .../fhir/convertors/loaders/BaseLoaderR3.java | 2 +- .../fhir/convertors/loaders/BaseLoaderR4.java | 2 +- .../fhir/convertors/loaders/BaseLoaderR5.java | 2 +- .../loaders/R2016MayToR5Loader.java | 2 +- .../fhir/convertors/loaders/R2ToR5Loader.java | 2 +- .../fhir/convertors/loaders/R3ToR5Loader.java | 2 +- .../fhir/convertors/loaders/R4ToR5Loader.java | 2 +- .../fhir/convertors/loaders/R5ToR5Loader.java | 2 +- .../fhir/convertors/misc/NUCCConvertor.java | 78 +++++++++---------- .../misc/NpmPackageVersionConverter.java | 2 +- .../misc/OIDBasedValueSetImporter.java | 6 +- .../convertors/misc/PhinVadsImporter.java | 6 +- .../convertors/misc/XMLPackageConvertor.java | 2 +- .../dstu3/context/SimpleWorkerContext.java | 2 +- .../fhir/r4/context/SimpleWorkerContext.java | 2 +- .../hl7/fhir/r4/model/BaseDateTimeType.java | 5 ++ .../org/hl7/fhir/r4/model/CodeSystem.java | 25 ++++++ .../org/hl7/fhir/r4/model/PrimitiveType.java | 3 + .../r4/terminologies/CodeSystemUtilities.java | 2 +- .../fhir/r4/test/utils/TestingUtilities.java | 4 +- .../fhir/r4/utils/NPMPackageGenerator.java | 4 +- .../hl7/fhir/r4/test/CDARoundTripTests.java | 4 +- .../hl7/fhir/r5/context/IWorkerContext.java | 4 +- .../fhir/r5/context/SimpleWorkerContext.java | 8 +- .../hl7/fhir/r5/model/BaseDateTimeType.java | 5 ++ .../org/hl7/fhir/r5/model/PrimitiveType.java | 4 + .../fhir/r5/test/utils/TestingUtilities.java | 4 +- .../fhir/r5/utils/NPMPackageGenerator.java | 6 +- .../hl7/fhir/r5/test/CDARoundTripTests.java | 4 +- .../org/hl7/fhir/r5/test/NpmPackageTests.java | 2 +- .../org/hl7/fhir/r5/test/ParsingTests.java | 6 +- .../fhir/r5/test/SnapShotGenerationTests.java | 6 +- .../r5/test/StructureMapUtilitiesTest.java | 4 +- .../org/hl7/fhir/r5/test/XmlParserTests.java | 4 +- .../hl7/fhir/utilities/VersionUtilities.java | 2 +- .../BasePackageCacheManager.java | 2 +- .../{cache => npm}/CachingPackageClient.java | 2 +- .../FilesystemPackageCacheManager.java | 4 +- .../{cache => npm}/IPackageCacheManager.java | 2 +- .../utilities/{cache => npm}/NpmPackage.java | 6 +- .../NpmPackageIndexBuilder.java | 2 +- .../{cache => npm}/PackageClient.java | 2 +- .../{cache => npm}/PackageGenerator.java | 2 +- .../{cache => npm}/PackageHacker.java | 2 +- .../{cache => npm}/ToolsVersion.java | 2 +- .../tests/CachingPackageClientTests.java | 4 +- .../utilities/tests/PackageCacheTests.java | 6 +- .../validation/packages/PackageValidator.java | 10 +-- .../comparison/tests/ComparisonTests.java | 6 +- .../conversion/tests/R3R4ConversionTests.java | 4 +- .../conversion/tests/UtilitiesXTests.java | 5 +- 52 files changed, 161 insertions(+), 128 deletions(-) rename org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/{cache => npm}/BasePackageCacheManager.java (99%) rename org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/{cache => npm}/CachingPackageClient.java (97%) rename org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/{cache => npm}/FilesystemPackageCacheManager.java (99%) rename org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/{cache => npm}/IPackageCacheManager.java (94%) rename org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/{cache => npm}/NpmPackage.java (99%) rename org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/{cache => npm}/NpmPackageIndexBuilder.java (97%) rename org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/{cache => npm}/PackageClient.java (99%) rename org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/{cache => npm}/PackageGenerator.java (99%) rename org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/{cache => npm}/PackageHacker.java (97%) rename org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/{cache => npm}/ToolsVersion.java (97%) diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/ExtensionDefinitionGenerator.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/ExtensionDefinitionGenerator.java index a5f2d838f..47a597ee3 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/ExtensionDefinitionGenerator.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/ExtensionDefinitionGenerator.java @@ -65,10 +65,10 @@ import org.hl7.fhir.r4.model.UriType; import org.hl7.fhir.r4.utils.NPMPackageGenerator; import org.hl7.fhir.r4.utils.NPMPackageGenerator.Category; import org.hl7.fhir.utilities.Utilities; -import org.hl7.fhir.utilities.cache.NpmPackage; -import org.hl7.fhir.utilities.cache.FilesystemPackageCacheManager; -import org.hl7.fhir.utilities.cache.PackageGenerator.PackageType; -import org.hl7.fhir.utilities.cache.ToolsVersion; +import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; +import org.hl7.fhir.utilities.npm.NpmPackage; +import org.hl7.fhir.utilities.npm.ToolsVersion; +import org.hl7.fhir.utilities.npm.PackageGenerator.PackageType; import com.google.gson.JsonArray; import com.google.gson.JsonObject; diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/BaseLoaderR3.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/BaseLoaderR3.java index 7b18144bb..758f97223 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/BaseLoaderR3.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/BaseLoaderR3.java @@ -5,7 +5,7 @@ import org.hl7.fhir.dstu3.model.Bundle; import org.hl7.fhir.dstu3.model.ElementDefinition; import org.hl7.fhir.dstu3.model.Resource; import org.hl7.fhir.dstu3.model.StructureDefinition; -import org.hl7.fhir.utilities.cache.NpmPackage; +import org.hl7.fhir.utilities.npm.NpmPackage; import java.util.ArrayList; import java.util.List; diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/BaseLoaderR4.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/BaseLoaderR4.java index 06c9aefad..8b0ed82a7 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/BaseLoaderR4.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/BaseLoaderR4.java @@ -6,7 +6,7 @@ import org.hl7.fhir.r4.model.CanonicalType; import org.hl7.fhir.r4.model.ElementDefinition; import org.hl7.fhir.r4.model.Resource; import org.hl7.fhir.r4.model.StructureDefinition; -import org.hl7.fhir.utilities.cache.NpmPackage; +import org.hl7.fhir.utilities.npm.NpmPackage; import java.util.ArrayList; import java.util.List; diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/BaseLoaderR5.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/BaseLoaderR5.java index f051fe763..43642a52c 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/BaseLoaderR5.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/BaseLoaderR5.java @@ -8,7 +8,7 @@ import org.hl7.fhir.r5.model.ElementDefinition; import org.hl7.fhir.r5.model.Resource; import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.utilities.VersionUtilities; -import org.hl7.fhir.utilities.cache.NpmPackage; +import org.hl7.fhir.utilities.npm.NpmPackage; import com.google.gson.JsonSyntaxException; diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/R2016MayToR5Loader.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/R2016MayToR5Loader.java index 054ad92fd..4aa7b132a 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/R2016MayToR5Loader.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/R2016MayToR5Loader.java @@ -55,9 +55,9 @@ import org.hl7.fhir.r5.model.CodeSystem; import org.hl7.fhir.r5.model.ElementDefinition; import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind; +import org.hl7.fhir.utilities.npm.NpmPackage; import org.hl7.fhir.r5.model.UriType; import org.hl7.fhir.r5.model.ValueSet; -import org.hl7.fhir.utilities.cache.NpmPackage; import com.google.gson.JsonSyntaxException; diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/R2ToR5Loader.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/R2ToR5Loader.java index a2af79bfe..07f64c869 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/R2ToR5Loader.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/R2ToR5Loader.java @@ -56,9 +56,9 @@ import org.hl7.fhir.r5.model.CodeSystem; import org.hl7.fhir.r5.model.ElementDefinition; import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind; +import org.hl7.fhir.utilities.npm.NpmPackage; import org.hl7.fhir.r5.model.UriType; import org.hl7.fhir.r5.model.ValueSet; -import org.hl7.fhir.utilities.cache.NpmPackage; import com.google.gson.JsonSyntaxException; diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/R3ToR5Loader.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/R3ToR5Loader.java index 24439f069..07feac9ab 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/R3ToR5Loader.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/R3ToR5Loader.java @@ -56,9 +56,9 @@ import org.hl7.fhir.r5.model.ElementDefinition; import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent; import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind; +import org.hl7.fhir.utilities.npm.NpmPackage; import org.hl7.fhir.r5.model.UriType; import org.hl7.fhir.r5.model.ValueSet; -import org.hl7.fhir.utilities.cache.NpmPackage; import com.google.gson.JsonSyntaxException; diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/R4ToR5Loader.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/R4ToR5Loader.java index 8df1eef65..fa8af1b5f 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/R4ToR5Loader.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/R4ToR5Loader.java @@ -56,9 +56,9 @@ import org.hl7.fhir.r5.model.ElementDefinition; import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent; import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind; +import org.hl7.fhir.utilities.npm.NpmPackage; import org.hl7.fhir.r5.model.UriType; import org.hl7.fhir.r5.model.ValueSet; -import org.hl7.fhir.utilities.cache.NpmPackage; import com.google.gson.JsonSyntaxException; diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/R5ToR5Loader.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/R5ToR5Loader.java index dd67566e1..a71cb3705 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/R5ToR5Loader.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/R5ToR5Loader.java @@ -55,9 +55,9 @@ import org.hl7.fhir.r5.model.ElementDefinition; import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent; import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind; +import org.hl7.fhir.utilities.npm.NpmPackage; import org.hl7.fhir.r5.model.UriType; import org.hl7.fhir.r5.model.ValueSet; -import org.hl7.fhir.utilities.cache.NpmPackage; import com.google.gson.JsonSyntaxException; diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/NUCCConvertor.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/NUCCConvertor.java index 777768c59..7c677c3da 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/NUCCConvertor.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/NUCCConvertor.java @@ -35,30 +35,31 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; -import org.hl7.fhir.dstu3.formats.IParser.OutputStyle; -import org.hl7.fhir.dstu3.formats.XmlParser; -import org.hl7.fhir.dstu3.model.CodeSystem; -import org.hl7.fhir.dstu3.model.CodeSystem.CodeSystemContentMode; -import org.hl7.fhir.dstu3.model.CodeSystem.CodeSystemHierarchyMeaning; -import org.hl7.fhir.dstu3.model.CodeSystem.ConceptDefinitionComponent; -import org.hl7.fhir.dstu3.model.DateTimeType; -import org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus; -import org.hl7.fhir.dstu3.terminologies.CodeSystemUtilities; -import org.hl7.fhir.dstu3.utils.ToolingExtensions; +import org.hl7.fhir.r4.formats.IParser.OutputStyle; +import org.hl7.fhir.r4.formats.XmlParser; +import org.hl7.fhir.r4.model.CodeSystem; +import org.hl7.fhir.r4.model.CodeSystem.CodeSystemContentMode; +import org.hl7.fhir.r4.model.CodeSystem.CodeSystemHierarchyMeaning; +import org.hl7.fhir.r4.model.CodeSystem.ConceptDefinitionComponent; +import org.hl7.fhir.r4.model.CodeSystem.PropertyType; +import org.hl7.fhir.r4.model.DateTimeType; +import org.hl7.fhir.r4.model.Enumerations.PublicationStatus; +import org.hl7.fhir.r4.model.StringType; +import org.hl7.fhir.r4.terminologies.CodeSystemUtilities; +import org.hl7.fhir.r4.utils.ToolingExtensions; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRFormatError; +import org.hl7.fhir.r4.formats.JsonParser; import org.hl7.fhir.utilities.CSVReader; import org.hl7.fhir.utilities.Utilities; public class NUCCConvertor { - private String[] last = new String[2]; - private ConceptDefinitionComponent[] concepts = new ConceptDefinitionComponent[2]; public static void main(String[] args) throws Exception { new NUCCConvertor().execute(); } - public void execute() throws IOException, FHIRException { + public void execute() throws IOException, FHIRException { CSVReader csv = new CSVReader(new FileInputStream("c:\\temp\\nucc.csv")); CodeSystem cs = new CodeSystem(); cs.setId("nucc-provider-taxonomy"); @@ -66,50 +67,41 @@ public class NUCCConvertor { cs.setName("NUCC Provider Taxonomy"); cs.setDateElement(new DateTimeType()); cs.setDescription("The Health Care Provider Taxonomy code is a unique alphanumeric code, ten characters in length. The code set is structured into three distinct 'Levels' including Provider Type, Classification, and Area of Specialization"); - cs.setCopyright("See NUCC copyright statement"); + cs.setCopyright("Vendors must request a license to include this in a product per the following: 'Vendors interested in incorporating the Health Care Provider Taxonomy code set into their commercial products must complete the license request form found on the CSV page.' Using the form at the url listed. The preamble is reproduced below: http://www.nucc.org/index.php?option=com_content&view=article&id=111&Itemid=110"); cs.setStatus(PublicationStatus.ACTIVE); cs.setContent(CodeSystemContentMode.COMPLETE); cs.setExperimental(false); cs.setValueSet("http://hl7.org/fhir/ValueSet/nucc-provider-taxonomy"); cs.setHierarchyMeaning(CodeSystemHierarchyMeaning.CLASSIFIEDWITH); + cs.addProperty().setCode("grouping").setType(PropertyType.STRING).setDescription("A major grouping of service(s) or occupation(s) of health care providers. For example: Allopathic & Osteopathic Physicians, Dental Providers, Hospitals, etc"); + cs.addProperty().setCode("classification").setType(PropertyType.STRING).setDescription("A more specific service or occupation related to the Provider Grouping.e"); + cs.addProperty().setCode("specialization").setType(PropertyType.STRING).setDescription("A more specialized area of the Classification in which a provider chooses to practice or make services available."); csv.parseLine(); - while (csv.ready()) - { + while (csv.ready()) { String[] values = csv.parseLine(); processLine(cs, values); } csv.close(); - new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream("c:\\temp\\nucc.xml"), cs); + cs.sort(); + new JsonParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream("c:\\temp\\nucc.json"), cs); } private void processLine(CodeSystem cs, String[] values) throws FHIRFormatError { - if (!values[1].equals(last[0])) { - last[1] = ""; - last[0] = values[1]; - concepts[0] = new ConceptDefinitionComponent(); - cs.getConcept().add(concepts[0]); - concepts[0].setDisplay(values[1]); - concepts[0].setCode("base-"+Integer.toString(cs.getConcept().size())); - CodeSystemUtilities.setNotSelectable(cs, concepts[0]); + ConceptDefinitionComponent cc = new ConceptDefinitionComponent(); + cs.getConcept().add(cc); + cc.setCode(values[0]); + cc.setDisplay(values[4]); + if (!Utilities.noString(values[1])) { + cc.addProperty().setCode("grouping").setValue(new StringType(values[1])); } - if (!values[2].equals(last[1])) { - last[1] = values[2]; - concepts[1] = new ConceptDefinitionComponent(); - concepts[0].getConcept().add(concepts[1]); - concepts[1].setCode(values[0]); - concepts[1].setDisplay(values[2]); - concepts[1].setDefinition(values[4]); - if (values.length > 5 && !Utilities.noString(values[5])) - ToolingExtensions.addCSComment(concepts[1], values[5]); - } else if (!Utilities.noString(values[3])) { - ConceptDefinitionComponent cc = new ConceptDefinitionComponent(); - concepts[1].getConcept().add(cc); - cc.setCode(values[0]); - cc.setDisplay(values[3]); - cc.setDefinition(values[4]); - if (values.length > 5 && !Utilities.noString(values[5])) - ToolingExtensions.addCSComment(cc, values[5]); + if (!Utilities.noString(values[2])) { + cc.addProperty().setCode("classification").setValue(new StringType(values[2])); } + if (!Utilities.noString(values[3])) { + cc.addProperty().setCode("specialization").setValue(new StringType(values[3])); + } + if (values.length > 5 && !Utilities.noString(values[5])) + cc.setDefinition(values[5]); } - + } \ No newline at end of file diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/NpmPackageVersionConverter.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/NpmPackageVersionConverter.java index f5da11936..4f63e27fa 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/NpmPackageVersionConverter.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/NpmPackageVersionConverter.java @@ -33,9 +33,9 @@ import org.hl7.fhir.r4.model.CodeSystem; import org.hl7.fhir.r4.model.ValueSet; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.VersionUtilities; -import org.hl7.fhir.utilities.cache.NpmPackageIndexBuilder; import org.hl7.fhir.utilities.json.JSONUtil; import org.hl7.fhir.utilities.json.JsonTrackingParser; +import org.hl7.fhir.utilities.npm.NpmPackageIndexBuilder; import com.google.common.base.Charsets; import com.google.gson.JsonArray; diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/OIDBasedValueSetImporter.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/OIDBasedValueSetImporter.java index 020a643e2..87475bfc1 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/OIDBasedValueSetImporter.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/OIDBasedValueSetImporter.java @@ -12,9 +12,9 @@ import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.context.SimpleWorkerContext; import org.hl7.fhir.r5.model.ValueSet; import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent; -import org.hl7.fhir.utilities.cache.FilesystemPackageCacheManager; -import org.hl7.fhir.utilities.cache.NpmPackage; -import org.hl7.fhir.utilities.cache.ToolsVersion; +import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; +import org.hl7.fhir.utilities.npm.NpmPackage; +import org.hl7.fhir.utilities.npm.ToolsVersion; import org.w3c.dom.Document; public class OIDBasedValueSetImporter { diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/PhinVadsImporter.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/PhinVadsImporter.java index 1f9a3db56..deafaf349 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/PhinVadsImporter.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/PhinVadsImporter.java @@ -19,9 +19,9 @@ import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent; import org.hl7.fhir.utilities.CSVReader; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; -import org.hl7.fhir.utilities.cache.FilesystemPackageCacheManager; -import org.hl7.fhir.utilities.cache.NpmPackage; -import org.hl7.fhir.utilities.cache.ToolsVersion; +import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; +import org.hl7.fhir.utilities.npm.NpmPackage; +import org.hl7.fhir.utilities.npm.ToolsVersion; public class PhinVadsImporter extends OIDBasedValueSetImporter { diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/XMLPackageConvertor.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/XMLPackageConvertor.java index 67d0e97ac..c359c4d71 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/XMLPackageConvertor.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/XMLPackageConvertor.java @@ -6,7 +6,7 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.util.Map.Entry; -import org.hl7.fhir.utilities.cache.NpmPackage; +import org.hl7.fhir.utilities.npm.NpmPackage; import com.google.gson.JsonElement; import com.google.gson.JsonObject; diff --git a/org.hl7.fhir.dstu3/src/main/java/org/hl7/fhir/dstu3/context/SimpleWorkerContext.java b/org.hl7.fhir.dstu3/src/main/java/org/hl7/fhir/dstu3/context/SimpleWorkerContext.java index 18b4833e7..080ed1952 100644 --- a/org.hl7.fhir.dstu3/src/main/java/org/hl7/fhir/dstu3/context/SimpleWorkerContext.java +++ b/org.hl7.fhir.dstu3/src/main/java/org/hl7/fhir/dstu3/context/SimpleWorkerContext.java @@ -89,7 +89,7 @@ import org.hl7.fhir.exceptions.FHIRFormatError; import org.hl7.fhir.utilities.CSFileInputStream; import org.hl7.fhir.utilities.OIDUtils; import org.hl7.fhir.utilities.Utilities; -import org.hl7.fhir.utilities.cache.NpmPackage; +import org.hl7.fhir.utilities.npm.NpmPackage; import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType; import org.hl7.fhir.utilities.validation.ValidationMessage.Source; diff --git a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/context/SimpleWorkerContext.java b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/context/SimpleWorkerContext.java index 78718cce6..72a0f050c 100644 --- a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/context/SimpleWorkerContext.java +++ b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/context/SimpleWorkerContext.java @@ -79,7 +79,7 @@ import org.hl7.fhir.r4.utils.IResourceValidator; import org.hl7.fhir.r4.utils.NarrativeGenerator; import org.hl7.fhir.utilities.CSFileInputStream; import org.hl7.fhir.utilities.Utilities; -import org.hl7.fhir.utilities.cache.NpmPackage; +import org.hl7.fhir.utilities.npm.NpmPackage; import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType; import org.hl7.fhir.utilities.validation.ValidationMessage.Source; diff --git a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/model/BaseDateTimeType.java b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/model/BaseDateTimeType.java index 04c9a3429..699db4c0e 100644 --- a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/model/BaseDateTimeType.java +++ b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/model/BaseDateTimeType.java @@ -939,4 +939,9 @@ public abstract class BaseDateTimeType extends PrimitiveType { } + @Override + public String fpValue() { + return "@"+primitiveValue(); + } + } \ No newline at end of file diff --git a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/model/CodeSystem.java b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/model/CodeSystem.java index 946f80d2e..43a1b69ea 100644 --- a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/model/CodeSystem.java +++ b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/model/CodeSystem.java @@ -37,6 +37,7 @@ package org.hl7.fhir.r4.model; import java.util.*; import org.hl7.fhir.utilities.Utilities; +import org.hl7.fhir.r4.model.CodeSystem.ConceptDefinitionComponentSorter; import org.hl7.fhir.r4.model.Enumerations.*; import ca.uhn.fhir.model.api.annotation.ResourceDef; import ca.uhn.fhir.model.api.annotation.SearchParamDefinition; @@ -5049,6 +5050,30 @@ public class CodeSystem extends MetadataResource { return null; } + public class ConceptDefinitionComponentSorter implements Comparator { + @Override + public int compare(ConceptDefinitionComponent l, ConceptDefinitionComponent r) { + return l.getCode().compareTo(r.getCode()); + } + } + + public void sort() { + sort(getConcept(), new ConceptDefinitionComponentSorter()); + } + + public void sort(List list, Comparator comp) { + Collections.sort(list, comp); + for (ConceptDefinitionComponent def : list) { + if (def.hasConcept()) { + sort (def.getConcept(), comp); + } + } + } + + public void sort(Comparator comp) { + sort(getConcept(), comp); + } + // end addition } \ No newline at end of file diff --git a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/model/PrimitiveType.java b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/model/PrimitiveType.java index 30df38036..4b8a95ca8 100644 --- a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/model/PrimitiveType.java +++ b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/model/PrimitiveType.java @@ -249,4 +249,7 @@ public abstract class PrimitiveType extends Type implements IPrimitiveType return StringUtils.isNotBlank(getValueAsString()); } + public String fpValue() { + return primitiveValue(); + } } \ No newline at end of file diff --git a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/terminologies/CodeSystemUtilities.java b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/terminologies/CodeSystemUtilities.java index da74a6e0f..f4b21442b 100644 --- a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/terminologies/CodeSystemUtilities.java +++ b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/terminologies/CodeSystemUtilities.java @@ -67,7 +67,7 @@ public class CodeSystemUtilities { public static void setNotSelectable(CodeSystem cs, ConceptDefinitionComponent concept) throws FHIRFormatError { defineNotSelectableProperty(cs); - ConceptPropertyComponent p = getProperty(concept, "notSelectable"); + ConceptPropertyComponent p = getProperty(concept, "abstract"); if (p != null) p.setValue(new BooleanType(true)); else diff --git a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/test/utils/TestingUtilities.java b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/test/utils/TestingUtilities.java index 019e639df..5fb2074a6 100644 --- a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/test/utils/TestingUtilities.java +++ b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/test/utils/TestingUtilities.java @@ -50,8 +50,8 @@ import org.hl7.fhir.r4.model.Parameters; import org.hl7.fhir.utilities.CSFile; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; -import org.hl7.fhir.utilities.cache.FilesystemPackageCacheManager; -import org.hl7.fhir.utilities.cache.ToolsVersion; +import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; +import org.hl7.fhir.utilities.npm.ToolsVersion; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; diff --git a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/NPMPackageGenerator.java b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/NPMPackageGenerator.java index 16577c02a..9b6ce7b4f 100644 --- a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/NPMPackageGenerator.java +++ b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/NPMPackageGenerator.java @@ -58,8 +58,8 @@ import org.hl7.fhir.r4.model.ImplementationGuide.ImplementationGuideDependsOnCom import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; -import org.hl7.fhir.utilities.cache.PackageGenerator.PackageType; -import org.hl7.fhir.utilities.cache.ToolsVersion; +import org.hl7.fhir.utilities.npm.ToolsVersion; +import org.hl7.fhir.utilities.npm.PackageGenerator.PackageType; import com.google.gson.Gson; import com.google.gson.GsonBuilder; diff --git a/org.hl7.fhir.r4/src/test/java/org/hl7/fhir/r4/test/CDARoundTripTests.java b/org.hl7.fhir.r4/src/test/java/org/hl7/fhir/r4/test/CDARoundTripTests.java index ca1be1254..921c4bbba 100644 --- a/org.hl7.fhir.r4/src/test/java/org/hl7/fhir/r4/test/CDARoundTripTests.java +++ b/org.hl7.fhir.r4/src/test/java/org/hl7/fhir/r4/test/CDARoundTripTests.java @@ -8,8 +8,8 @@ import org.hl7.fhir.r4.elementmodel.Element; import org.hl7.fhir.r4.elementmodel.Manager; import org.hl7.fhir.r4.elementmodel.Manager.FhirFormat; import org.hl7.fhir.r4.formats.IParser.OutputStyle; -import org.hl7.fhir.utilities.cache.FilesystemPackageCacheManager; -import org.hl7.fhir.utilities.cache.ToolsVersion; +import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; +import org.hl7.fhir.utilities.npm.ToolsVersion; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/IWorkerContext.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/IWorkerContext.java index 8a0593606..72b79b4bd 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/IWorkerContext.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/IWorkerContext.java @@ -67,8 +67,8 @@ import org.hl7.fhir.r5.terminologies.ValueSetExpander.ValueSetExpansionOutcome; import org.hl7.fhir.r5.utils.IResourceValidator; import org.hl7.fhir.utilities.TimeTracker; import org.hl7.fhir.utilities.TranslationServices; -import org.hl7.fhir.utilities.cache.BasePackageCacheManager; -import org.hl7.fhir.utilities.cache.NpmPackage; +import org.hl7.fhir.utilities.npm.BasePackageCacheManager; +import org.hl7.fhir.utilities.npm.NpmPackage; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity; import org.hl7.fhir.utilities.validation.ValidationOptions; diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/SimpleWorkerContext.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/SimpleWorkerContext.java index 207d6ec29..87b8571f7 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/SimpleWorkerContext.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/SimpleWorkerContext.java @@ -81,11 +81,11 @@ import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.TimeTracker; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.VersionUtilities; -import org.hl7.fhir.utilities.cache.BasePackageCacheManager; -import org.hl7.fhir.utilities.cache.FilesystemPackageCacheManager; -import org.hl7.fhir.utilities.cache.NpmPackage; -import org.hl7.fhir.utilities.cache.NpmPackage.PackageResourceInformation; import org.hl7.fhir.utilities.i18n.I18nConstants; +import org.hl7.fhir.utilities.npm.BasePackageCacheManager; +import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; +import org.hl7.fhir.utilities.npm.NpmPackage; +import org.hl7.fhir.utilities.npm.NpmPackage.PackageResourceInformation; import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType; import org.hl7.fhir.utilities.validation.ValidationMessage.Source; diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/BaseDateTimeType.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/BaseDateTimeType.java index 6f68f819d..b9dcb4ace 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/BaseDateTimeType.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/BaseDateTimeType.java @@ -1006,4 +1006,9 @@ public abstract class BaseDateTimeType extends PrimitiveType { } } + @Override + public String fpValue() { + return "@"+primitiveValue(); + } + } \ No newline at end of file diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/PrimitiveType.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/PrimitiveType.java index b42d3d04e..49ac41018 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/PrimitiveType.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/PrimitiveType.java @@ -248,4 +248,8 @@ public abstract class PrimitiveType extends DataType implements IPrimitiveTyp public boolean hasPrimitiveValue() { return StringUtils.isNotBlank(getValueAsString()); } + + public String fpValue() { + return primitiveValue(); + } } \ No newline at end of file diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/test/utils/TestingUtilities.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/test/utils/TestingUtilities.java index c7fb031c0..071fc44a9 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/test/utils/TestingUtilities.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/test/utils/TestingUtilities.java @@ -22,8 +22,8 @@ import org.hl7.fhir.utilities.CSFile; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.VersionUtilities; -import org.hl7.fhir.utilities.cache.FilesystemPackageCacheManager; -import org.hl7.fhir.utilities.cache.ToolsVersion; +import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; +import org.hl7.fhir.utilities.npm.ToolsVersion; import org.hl7.fhir.utilities.tests.BaseTestingUtilities; import org.w3c.dom.Document; import org.w3c.dom.Element; diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/NPMPackageGenerator.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/NPMPackageGenerator.java index 0a46a7fcf..5a8d2fb93 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/NPMPackageGenerator.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/NPMPackageGenerator.java @@ -62,9 +62,9 @@ import org.hl7.fhir.r5.model.ImplementationGuide.ImplementationGuideDependsOnCom import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; -import org.hl7.fhir.utilities.cache.NpmPackageIndexBuilder; -import org.hl7.fhir.utilities.cache.PackageGenerator.PackageType; -import org.hl7.fhir.utilities.cache.ToolsVersion; +import org.hl7.fhir.utilities.npm.NpmPackageIndexBuilder; +import org.hl7.fhir.utilities.npm.ToolsVersion; +import org.hl7.fhir.utilities.npm.PackageGenerator.PackageType; import com.google.gson.Gson; import com.google.gson.GsonBuilder; diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/CDARoundTripTests.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/CDARoundTripTests.java index 0573d8740..13408d869 100644 --- a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/CDARoundTripTests.java +++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/CDARoundTripTests.java @@ -13,8 +13,8 @@ import org.hl7.fhir.r5.formats.IParser.OutputStyle; import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.r5.test.utils.TestingUtilities; import org.hl7.fhir.r5.utils.FHIRPathEngine; -import org.hl7.fhir.utilities.cache.FilesystemPackageCacheManager; -import org.hl7.fhir.utilities.cache.ToolsVersion; +import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; +import org.hl7.fhir.utilities.npm.ToolsVersion; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/NpmPackageTests.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/NpmPackageTests.java index c9233871f..b115e42ea 100644 --- a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/NpmPackageTests.java +++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/NpmPackageTests.java @@ -11,7 +11,7 @@ import java.util.zip.ZipInputStream; import org.hl7.fhir.r5.test.utils.TestingUtilities; import org.hl7.fhir.utilities.Utilities; -import org.hl7.fhir.utilities.cache.NpmPackage; +import org.hl7.fhir.utilities.npm.NpmPackage; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/ParsingTests.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/ParsingTests.java index 33bbb6ab8..99a5c4b3c 100644 --- a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/ParsingTests.java +++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/ParsingTests.java @@ -43,9 +43,9 @@ import org.hl7.fhir.r5.utils.IResourceValidator; import org.hl7.fhir.r5.utils.XVerExtensionManager; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; -import org.hl7.fhir.utilities.cache.NpmPackage; -import org.hl7.fhir.utilities.cache.FilesystemPackageCacheManager; -import org.hl7.fhir.utilities.cache.ToolsVersion; +import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; +import org.hl7.fhir.utilities.npm.NpmPackage; +import org.hl7.fhir.utilities.npm.ToolsVersion; import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity; import org.hl7.fhir.utilities.xml.XMLUtil; diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/SnapShotGenerationTests.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/SnapShotGenerationTests.java index b1cdb6b78..d18e7dff1 100644 --- a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/SnapShotGenerationTests.java +++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/SnapShotGenerationTests.java @@ -42,9 +42,9 @@ import org.hl7.fhir.r5.utils.FHIRPathEngine.IEvaluationContext; import org.hl7.fhir.r5.utils.IResourceValidator; import org.hl7.fhir.r5.utils.XVerExtensionManager; import org.hl7.fhir.utilities.Utilities; -import org.hl7.fhir.utilities.cache.NpmPackage; -import org.hl7.fhir.utilities.cache.FilesystemPackageCacheManager; -import org.hl7.fhir.utilities.cache.ToolsVersion; +import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; +import org.hl7.fhir.utilities.npm.NpmPackage; +import org.hl7.fhir.utilities.npm.ToolsVersion; import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity; import org.hl7.fhir.utilities.xml.XMLUtil; diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/StructureMapUtilitiesTest.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/StructureMapUtilitiesTest.java index dc9285a84..f3aa9ea25 100644 --- a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/StructureMapUtilitiesTest.java +++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/StructureMapUtilitiesTest.java @@ -12,8 +12,8 @@ import org.hl7.fhir.r5.model.StructureMap.StructureMapGroupRuleTargetComponent; import org.hl7.fhir.r5.test.utils.TestingUtilities; import org.hl7.fhir.r5.utils.StructureMapUtilities; import org.hl7.fhir.r5.utils.StructureMapUtilities.ITransformerServices; -import org.hl7.fhir.utilities.cache.FilesystemPackageCacheManager; -import org.hl7.fhir.utilities.cache.ToolsVersion; +import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; +import org.hl7.fhir.utilities.npm.ToolsVersion; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/XmlParserTests.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/XmlParserTests.java index bda09cbf3..c7f61adda 100644 --- a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/XmlParserTests.java +++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/XmlParserTests.java @@ -11,8 +11,8 @@ import org.hl7.fhir.r5.formats.IParser.OutputStyle; import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.r5.test.utils.TestingUtilities; import org.hl7.fhir.r5.utils.FHIRPathEngine; -import org.hl7.fhir.utilities.cache.FilesystemPackageCacheManager; -import org.hl7.fhir.utilities.cache.ToolsVersion; +import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; +import org.hl7.fhir.utilities.npm.ToolsVersion; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/VersionUtilities.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/VersionUtilities.java index 83e69ed40..c74687d8b 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/VersionUtilities.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/VersionUtilities.java @@ -4,7 +4,7 @@ import java.util.ArrayList; import java.util.List; import org.hl7.fhir.exceptions.FHIRException; -import org.hl7.fhir.utilities.cache.NpmPackage; +import org.hl7.fhir.utilities.npm.NpmPackage; /* Copyright (c) 2011+, HL7, Inc. diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/BasePackageCacheManager.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/BasePackageCacheManager.java similarity index 99% rename from org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/BasePackageCacheManager.java rename to org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/BasePackageCacheManager.java index 5074396bd..c116eb058 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/BasePackageCacheManager.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/BasePackageCacheManager.java @@ -1,4 +1,4 @@ -package org.hl7.fhir.utilities.cache; +package org.hl7.fhir.utilities.npm; import org.apache.commons.lang3.Validate; import org.hl7.fhir.exceptions.FHIRException; diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/CachingPackageClient.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/CachingPackageClient.java similarity index 97% rename from org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/CachingPackageClient.java rename to org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/CachingPackageClient.java index 571dd59c9..e5812be8f 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/CachingPackageClient.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/CachingPackageClient.java @@ -1,4 +1,4 @@ -package org.hl7.fhir.utilities.cache; +package org.hl7.fhir.utilities.npm; import java.io.File; import java.io.FileInputStream; diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/FilesystemPackageCacheManager.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/FilesystemPackageCacheManager.java similarity index 99% rename from org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/FilesystemPackageCacheManager.java rename to org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/FilesystemPackageCacheManager.java index 4d6b9f11d..66f22cc17 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/FilesystemPackageCacheManager.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/FilesystemPackageCacheManager.java @@ -1,4 +1,4 @@ -package org.hl7.fhir.utilities.cache; +package org.hl7.fhir.utilities.npm; /* Copyright (c) 2011+, HL7, Inc. @@ -40,8 +40,8 @@ import org.hl7.fhir.utilities.IniFile; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.VersionUtilities; -import org.hl7.fhir.utilities.cache.NpmPackage.NpmPackageFolder; import org.hl7.fhir.utilities.json.JSONUtil; +import org.hl7.fhir.utilities.npm.NpmPackage.NpmPackageFolder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/IPackageCacheManager.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/IPackageCacheManager.java similarity index 94% rename from org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/IPackageCacheManager.java rename to org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/IPackageCacheManager.java index eaeeebc48..99e19e511 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/IPackageCacheManager.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/IPackageCacheManager.java @@ -1,4 +1,4 @@ -package org.hl7.fhir.utilities.cache; +package org.hl7.fhir.utilities.npm; import org.hl7.fhir.exceptions.FHIRException; diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/NpmPackage.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/NpmPackage.java similarity index 99% rename from org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/NpmPackage.java rename to org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/NpmPackage.java index f32ef1380..5f1415f62 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/NpmPackage.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/NpmPackage.java @@ -1,4 +1,4 @@ -package org.hl7.fhir.utilities.cache; +package org.hl7.fhir.utilities.npm; /* Copyright (c) 2011+, HL7, Inc. @@ -61,10 +61,10 @@ import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; -import org.hl7.fhir.utilities.cache.NpmPackage.PackageResourceInformationSorter; -import org.hl7.fhir.utilities.cache.PackageGenerator.PackageType; import org.hl7.fhir.utilities.json.JSONUtil; import org.hl7.fhir.utilities.json.JsonTrackingParser; +import org.hl7.fhir.utilities.npm.NpmPackage.PackageResourceInformationSorter; +import org.hl7.fhir.utilities.npm.PackageGenerator.PackageType; import com.google.gson.GsonBuilder; import com.google.gson.JsonArray; diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/NpmPackageIndexBuilder.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/NpmPackageIndexBuilder.java similarity index 97% rename from org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/NpmPackageIndexBuilder.java rename to org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/NpmPackageIndexBuilder.java index 5ae42d265..8d14a449b 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/NpmPackageIndexBuilder.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/NpmPackageIndexBuilder.java @@ -1,4 +1,4 @@ -package org.hl7.fhir.utilities.cache; +package org.hl7.fhir.utilities.npm; import java.io.File; import java.io.IOException; diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/PackageClient.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageClient.java similarity index 99% rename from org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/PackageClient.java rename to org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageClient.java index 16e92ae7b..18f9e434f 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/PackageClient.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageClient.java @@ -1,4 +1,4 @@ -package org.hl7.fhir.utilities.cache; +package org.hl7.fhir.utilities.npm; import com.google.gson.JsonArray; import com.google.gson.JsonElement; diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/PackageGenerator.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageGenerator.java similarity index 99% rename from org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/PackageGenerator.java rename to org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageGenerator.java index a39e537a7..d4d73c1a0 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/PackageGenerator.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageGenerator.java @@ -1,4 +1,4 @@ -package org.hl7.fhir.utilities.cache; +package org.hl7.fhir.utilities.npm; /* Copyright (c) 2011+, HL7, Inc. diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/PackageHacker.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageHacker.java similarity index 97% rename from org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/PackageHacker.java rename to org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageHacker.java index c9c2c7ebe..26e7d9637 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/PackageHacker.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageHacker.java @@ -1,4 +1,4 @@ -package org.hl7.fhir.utilities.cache; +package org.hl7.fhir.utilities.npm; import java.io.File; import java.io.FileInputStream; diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/ToolsVersion.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/ToolsVersion.java similarity index 97% rename from org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/ToolsVersion.java rename to org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/ToolsVersion.java index 7ece6c31e..018ad9c12 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/ToolsVersion.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/ToolsVersion.java @@ -1,4 +1,4 @@ -package org.hl7.fhir.utilities.cache; +package org.hl7.fhir.utilities.npm; /* Copyright (c) 2011+, HL7, Inc. diff --git a/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/tests/CachingPackageClientTests.java b/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/tests/CachingPackageClientTests.java index 2e897e910..a9d592118 100644 --- a/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/tests/CachingPackageClientTests.java +++ b/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/tests/CachingPackageClientTests.java @@ -1,7 +1,7 @@ package org.hl7.fhir.utilities.tests; -import org.hl7.fhir.utilities.cache.CachingPackageClient; -import org.hl7.fhir.utilities.cache.PackageClient.PackageInfo; +import org.hl7.fhir.utilities.npm.CachingPackageClient; +import org.hl7.fhir.utilities.npm.PackageClient.PackageInfo; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; diff --git a/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/tests/PackageCacheTests.java b/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/tests/PackageCacheTests.java index 8e8289fbd..05d38d4d8 100644 --- a/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/tests/PackageCacheTests.java +++ b/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/tests/PackageCacheTests.java @@ -1,9 +1,9 @@ package org.hl7.fhir.utilities.tests; import org.hl7.fhir.utilities.Utilities; -import org.hl7.fhir.utilities.cache.NpmPackage; -import org.hl7.fhir.utilities.cache.FilesystemPackageCacheManager; -import org.hl7.fhir.utilities.cache.ToolsVersion; +import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; +import org.hl7.fhir.utilities.npm.NpmPackage; +import org.hl7.fhir.utilities.npm.ToolsVersion; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/packages/PackageValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/packages/PackageValidator.java index 099f203c8..6304f71d4 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/packages/PackageValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/packages/PackageValidator.java @@ -7,11 +7,11 @@ import java.util.List; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRFormatError; import org.hl7.fhir.utilities.VersionUtilities; -import org.hl7.fhir.utilities.cache.NpmPackage; -import org.hl7.fhir.utilities.cache.FilesystemPackageCacheManager; -import org.hl7.fhir.utilities.cache.CachingPackageClient; -import org.hl7.fhir.utilities.cache.PackageClient.PackageInfo; -import org.hl7.fhir.utilities.cache.ToolsVersion; +import org.hl7.fhir.utilities.npm.CachingPackageClient; +import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; +import org.hl7.fhir.utilities.npm.NpmPackage; +import org.hl7.fhir.utilities.npm.ToolsVersion; +import org.hl7.fhir.utilities.npm.PackageClient.PackageInfo; public class PackageValidator { diff --git a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/comparison/tests/ComparisonTests.java b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/comparison/tests/ComparisonTests.java index 367977e38..d0cdf5425 100644 --- a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/comparison/tests/ComparisonTests.java +++ b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/comparison/tests/ComparisonTests.java @@ -38,9 +38,9 @@ import org.hl7.fhir.r5.test.utils.TestingUtilities; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.VersionUtilities; -import org.hl7.fhir.utilities.cache.NpmPackage; -import org.hl7.fhir.utilities.cache.FilesystemPackageCacheManager; -import org.hl7.fhir.utilities.cache.ToolsVersion; +import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; +import org.hl7.fhir.utilities.npm.NpmPackage; +import org.hl7.fhir.utilities.npm.ToolsVersion; import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity; import org.hl7.fhir.utilities.xhtml.XhtmlComposer; diff --git a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/conversion/tests/R3R4ConversionTests.java b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/conversion/tests/R3R4ConversionTests.java index 03a5ba941..ba1bcce23 100644 --- a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/conversion/tests/R3R4ConversionTests.java +++ b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/conversion/tests/R3R4ConversionTests.java @@ -22,8 +22,8 @@ import org.hl7.fhir.r4.utils.StructureMapUtilities.ITransformerServices; import org.hl7.fhir.utilities.IniFile; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; -import org.hl7.fhir.utilities.cache.FilesystemPackageCacheManager; -import org.hl7.fhir.utilities.cache.ToolsVersion; +import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; +import org.hl7.fhir.utilities.npm.ToolsVersion; import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity; import org.junit.jupiter.api.Disabled; diff --git a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/conversion/tests/UtilitiesXTests.java b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/conversion/tests/UtilitiesXTests.java index 0cb9c8016..1e65b8cb7 100644 --- a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/conversion/tests/UtilitiesXTests.java +++ b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/conversion/tests/UtilitiesXTests.java @@ -59,9 +59,8 @@ import org.hl7.fhir.utilities.CSFile; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.VersionUtilities; -import org.hl7.fhir.utilities.cache.FilesystemPackageCacheManager; -import org.hl7.fhir.utilities.cache.ToolsVersion; - +import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; +import org.hl7.fhir.utilities.npm.ToolsVersion; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; From 6407f65353ec2a54c7543d6796539ac695bac997 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Wed, 30 Sep 2020 09:39:02 +1000 Subject: [PATCH 63/73] update to POM --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5829bbfe7..219d4e271 100644 --- a/pom.xml +++ b/pom.xml @@ -19,7 +19,7 @@ 5.1.0 - 1.1.44 + 1.1.45-SNAPSHOT 5.6.2 3.0.0-M4 0.8.5 From 46d1987cd0322d13846a8038b0b279324eed94d9 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Wed, 30 Sep 2020 12:10:59 +1000 Subject: [PATCH 64/73] refactor FHIRPath to report error locations for run time errors --- .../org/hl7/fhir/r4/model/ExpressionNode.java | 26 +- .../java/org/hl7/fhir/r4/utils/FHIRLexer.java | 2 +- .../org/hl7/fhir/r4/utils/FHIRPathEngine.java | 493 ++++++------- .../org/hl7/fhir/r5/model/ExpressionNode.java | 25 +- .../java/org/hl7/fhir/r5/utils/FHIRLexer.java | 2 +- .../org/hl7/fhir/r5/utils/FHIRPathEngine.java | 696 +++++++++--------- .../org/hl7/fhir/r5/test/FHIRPathTests.java | 3 + .../fhir/exceptions/PathEngineException.java | 59 +- .../hl7/fhir/utilities/SourceLocation.java | 27 + 9 files changed, 684 insertions(+), 649 deletions(-) create mode 100644 org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/SourceLocation.java diff --git a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/model/ExpressionNode.java b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/model/ExpressionNode.java index a061937a9..3ed27a087 100644 --- a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/model/ExpressionNode.java +++ b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/model/ExpressionNode.java @@ -34,6 +34,7 @@ package org.hl7.fhir.r4.model; import java.util.ArrayList; import java.util.List; +import org.hl7.fhir.utilities.SourceLocation; import org.hl7.fhir.utilities.Utilities; public class ExpressionNode { @@ -41,31 +42,6 @@ public class ExpressionNode { public enum Kind { Name, Function, Constant, Group, Unary } - public static class SourceLocation { - private int line; - private int column; - public SourceLocation(int line, int column) { - super(); - this.line = line; - this.column = column; - } - public int getLine() { - return line; - } - public int getColumn() { - return column; - } - public void setLine(int line) { - this.line = line; - } - public void setColumn(int column) { - this.column = column; - } - - public String toString() { - return Integer.toString(line)+", "+Integer.toString(column); - } - } public enum Function { Custom, diff --git a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/FHIRLexer.java b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/FHIRLexer.java index 38df5e9a4..83619c66b 100644 --- a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/FHIRLexer.java +++ b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/FHIRLexer.java @@ -34,7 +34,7 @@ import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.r4.model.ExpressionNode; -import org.hl7.fhir.r4.model.ExpressionNode.SourceLocation; +import org.hl7.fhir.utilities.SourceLocation; import org.hl7.fhir.utilities.Utilities; // shared lexer for concrete syntaxes diff --git a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/FHIRPathEngine.java b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/FHIRPathEngine.java index 89f805006..7bc7ec1c0 100644 --- a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/FHIRPathEngine.java +++ b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/FHIRPathEngine.java @@ -19,6 +19,7 @@ import org.hl7.fhir.r4.model.StructureDefinition.TypeDerivationRule; import org.hl7.fhir.r4.model.TypeDetails.ProfiledType; import org.hl7.fhir.r4.utils.FHIRLexer.FHIRLexerException; import org.hl7.fhir.r4.utils.FHIRPathEngine.IEvaluationContext.FunctionDetails; +import org.hl7.fhir.utilities.SourceLocation; import org.hl7.fhir.utilities.TerminologyServiceOptions; import org.hl7.fhir.utilities.Utilities; @@ -414,10 +415,10 @@ public class FHIRPathEngine { } StructureDefinition sd = worker.fetchResource(StructureDefinition.class, ctxt); if (sd == null) - throw new PathEngineException("Unknown context "+context); - ElementDefinitionMatch ed = getElementDefinition(sd, context, true); + throw new PathEngineException("Unknown context "+context, expr.getStart(), expr.toString()); + ElementDefinitionMatch ed = getElementDefinition(sd, context, true, expr); if (ed == null) - throw new PathEngineException("Unknown context element "+context); + throw new PathEngineException("Unknown context element "+context, expr.getStart(), expr.toString()); if (ed.fixedType != null) types = new TypeDetails(CollectionStatus.SINGLETON, ed.fixedType); else if (ed.getDefinition().getType().isEmpty() || isAbstractType(ed.getDefinition().getType())) @@ -438,9 +439,9 @@ public class FHIRPathEngine { if (!context.contains(".")) { types = new TypeDetails(CollectionStatus.SINGLETON, sd.getUrl()); } else { - ElementDefinitionMatch ed = getElementDefinition(sd, context, true); + ElementDefinitionMatch ed = getElementDefinition(sd, context, true, expr); if (ed == null) - throw new PathEngineException("Unknown context element "+context); + throw new PathEngineException("Unknown context element "+context, expr.getStart(), expr.toString()); if (ed.fixedType != null) types = new TypeDetails(CollectionStatus.SINGLETON, ed.fixedType); else if (ed.getDefinition().getType().isEmpty() || isAbstractType(ed.getDefinition().getType())) @@ -1161,7 +1162,7 @@ public class FHIRPathEngine { work.addAll(work2); break; case Constant: - Base b = resolveConstant(context, exp.getConstant(), false); + Base b = resolveConstant(context, exp.getConstant(), false, exp); if (b != null) work.add(b); break; @@ -1177,15 +1178,15 @@ public class FHIRPathEngine { ExpressionNode next = exp.getOpNext(); ExpressionNode last = exp; while (next != null) { - List work2 = preOperate(work, last.getOperation()); + List work2 = preOperate(work, last.getOperation(), exp); if (work2 != null) work = work2; else if (last.getOperation() == Operation.Is || last.getOperation() == Operation.As) { work2 = executeTypeName(context, focus, next, false); - work = operate(context, work, last.getOperation(), work2); + work = operate(context, work, last.getOperation(), work2, last); } else { work2 = execute(context, focus, next, true); - work = operate(context, work, last.getOperation(), work2); + work = operate(context, work, last.getOperation(), work2, last); // System.out.println("Result of {'"+last.toString()+" "+last.getOperation().toCode()+" "+next.toString()+"'}: "+focus.toString()); } last = next; @@ -1206,7 +1207,7 @@ public class FHIRPathEngine { } - private List preOperate(List left, Operation operation) throws PathEngineException { + private List preOperate(List left, Operation operation, ExpressionNode expr) throws PathEngineException { if (left.size() == 0) return null; switch (operation) { @@ -1215,7 +1216,7 @@ public class FHIRPathEngine { case Or: return isBoolean(left, true) ? makeBoolean(true) : null; case Implies: - Equality v = asBool(left); + Equality v = asBool(left, expr); return v == Equality.False ? makeBoolean(true) : null; default: return null; @@ -1246,13 +1247,13 @@ public class FHIRPathEngine { else if (atEntry && exp.getName().equals("$total")) result.update(anything(CollectionStatus.UNORDERED)); else if (atEntry && focus == null) - result.update(executeContextType(context, exp.getName())); + result.update(executeContextType(context, exp.getName(), exp)); else { for (String s : focus.getTypes()) { result.update(executeType(s, exp, atEntry)); } if (result.hasNoTypes()) - throw new PathEngineException("The name "+exp.getName()+" is not valid for any of the possible types: "+focus.describe()); + throw new PathEngineException("The name "+exp.getName()+" is not valid for any of the possible types: "+focus.describe(), exp.getStart(), exp.toString()); } break; case Function: @@ -1262,7 +1263,7 @@ public class FHIRPathEngine { result.addType("integer"); break; case Constant: - result.update(resolveConstantType(context, exp.getConstant())); + result.update(resolveConstantType(context, exp.getConstant(), exp)); break; case Group: result.update(executeType(context, focus, exp.getGroup(), atEntry)); @@ -1282,7 +1283,7 @@ public class FHIRPathEngine { work = executeTypeName(context, focus, next, atEntry); else work = executeType(context, focus, next, atEntry); - result = operateTypes(result, last.getOperation(), work); + result = operateTypes(result, last.getOperation(), work, exp); last = next; next = next.getOpNext(); } @@ -1291,16 +1292,16 @@ public class FHIRPathEngine { return result; } - private Base resolveConstant(ExecutionContext context, Base constant, boolean beforeContext) throws PathEngineException { + private Base resolveConstant(ExecutionContext context, Base constant, boolean beforeContext, ExpressionNode expr) throws PathEngineException { if (!(constant instanceof FHIRConstant)) return constant; FHIRConstant c = (FHIRConstant) constant; if (c.getValue().startsWith("%")) { - return resolveConstant(context, c.getValue(), beforeContext); + return resolveConstant(context, c.getValue(), beforeContext, expr); } else if (c.getValue().startsWith("@")) { return processDateConstant(context.appInfo, c.getValue().substring(1)); } else - throw new PathEngineException("Invaild FHIR Constant "+c.getValue()); + throw new PathEngineException("Invaild FHIR Constant "+c.getValue(), expr.getStart(), expr.toString()); } private Base processDateConstant(Object appInfo, String value) throws PathEngineException { @@ -1322,7 +1323,7 @@ public class FHIRPathEngine { } - private Base resolveConstant(ExecutionContext context, String s, boolean beforeContext) throws PathEngineException { + private Base resolveConstant(ExecutionContext context, String s, boolean beforeContext, ExpressionNode expr) throws PathEngineException { if (s.equals("%sct")) return new StringType("http://snomed.info/sct").noExtensions(); else if (s.equals("%loinc")) @@ -1331,11 +1332,11 @@ public class FHIRPathEngine { return new StringType("http://unitsofmeasure.org").noExtensions(); else if (s.equals("%resource")) { if (context.focusResource == null) - throw new PathEngineException("Cannot use %resource in this context"); + throw new PathEngineException("Cannot use %resource in this context", expr.getStart(), expr.toString()); return context.focusResource; } else if (s.equals("%rootResource")) { if (context.rootResource == null) - throw new PathEngineException("Cannot use %rootResource in this context"); + throw new PathEngineException("Cannot use %rootResource in this context", expr.getStart(), expr.toString()); return context.rootResource; } else if (s.equals("%context")) { return context.context; @@ -1348,7 +1349,7 @@ public class FHIRPathEngine { else if (s.startsWith("%`ext-")) return new StringType("http://hl7.org/fhir/StructureDefinition/"+s.substring(6, s.length()-1)).noExtensions(); else if (hostServices == null) - throw new PathEngineException("Unknown fixed constant '"+s+"'"); + throw new PathEngineException("Unknown fixed constant '"+s+"'", expr.getStart(), expr.toString()); else return hostServices.resolveConstant(context.appInfo, s.substring(1), beforeContext); } @@ -1408,39 +1409,39 @@ public class FHIRPathEngine { } - private List operate(ExecutionContext context, List left, Operation operation, List right) throws FHIRException { + private List operate(ExecutionContext context, List left, Operation operation, List right, ExpressionNode expr) throws FHIRException { switch (operation) { case Equals: return opEquals(left, right); - case Equivalent: return opEquivalent(left, right); - case NotEquals: return opNotEquals(left, right); - case NotEquivalent: return opNotEquivalent(left, right); - case LessThan: return opLessThan(left, right); - case Greater: return opGreater(left, right); - case LessOrEqual: return opLessOrEqual(left, right); - case GreaterOrEqual: return opGreaterOrEqual(left, right); - case Union: return opUnion(left, right); - case In: return opIn(left, right); - case MemberOf: return opMemberOf(context, left, right); - case Contains: return opContains(left, right); - case Or: return opOr(left, right); - case And: return opAnd(left, right); - case Xor: return opXor(left, right); - case Implies: return opImplies(left, right); - case Plus: return opPlus(left, right); - case Times: return opTimes(left, right); - case Minus: return opMinus(left, right); - case Concatenate: return opConcatenate(left, right); - case DivideBy: return opDivideBy(left, right); - case Div: return opDiv(left, right); - case Mod: return opMod(left, right); - case Is: return opIs(left, right); - case As: return opAs(left, right); + case Equivalent: return opEquivalent(left, right, expr); + case NotEquals: return opNotEquals(left, right, expr); + case NotEquivalent: return opNotEquivalent(left, right, expr); + case LessThan: return opLessThan(left, right, expr); + case Greater: return opGreater(left, right, expr); + case LessOrEqual: return opLessOrEqual(left, right, expr); + case GreaterOrEqual: return opGreaterOrEqual(left, right, expr); + case Union: return opUnion(left, right, expr); + case In: return opIn(left, right, expr); + case MemberOf: return opMemberOf(context, left, right, expr); + case Contains: return opContains(left, right, expr); + case Or: return opOr(left, right, expr); + case And: return opAnd(left, right, expr); + case Xor: return opXor(left, right, expr); + case Implies: return opImplies(left, right, expr); + case Plus: return opPlus(left, right, expr); + case Times: return opTimes(left, right, expr); + case Minus: return opMinus(left, right, expr); + case Concatenate: return opConcatenate(left, right, expr); + case DivideBy: return opDivideBy(left, right, expr); + case Div: return opDiv(left, right, expr); + case Mod: return opMod(left, right, expr); + case Is: return opIs(left, right, expr); + case As: return opAs(left, right, expr); default: throw new Error("Not Done Yet: "+operation.toCode()); } } - private List opAs(List left, List right) { + private List opAs(List left, List right, ExpressionNode expr) { List result = new ArrayList<>(); if (right.size() != 1) return result; @@ -1455,7 +1456,7 @@ public class FHIRPathEngine { } - private List opIs(List left, List right) { + private List opIs(List left, List right, ExpressionNode expr) { List result = new ArrayList(); if (left.size() != 1 || right.size() != 1) result.add(new BooleanType(false).noExtensions()); @@ -1472,7 +1473,7 @@ public class FHIRPathEngine { } - private TypeDetails operateTypes(TypeDetails left, Operation operation, TypeDetails right) { + private TypeDetails operateTypes(TypeDetails left, Operation operation, TypeDetails right, ExpressionNode expr) { switch (operation) { case Equals: return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); case Equivalent: return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); @@ -1518,7 +1519,7 @@ public class FHIRPathEngine { if (right.hasType(worker, "Quantity")) { result.addType(left.getType()); } else { - throw new PathEngineException(String.format("Error in date arithmetic: Unable to add type {0} to {1}", right.getType(), left.getType())); + throw new PathEngineException(String.format("Error in date arithmetic: Unable to add type {0} to {1}", right.getType(), left.getType()), expr.getStart(), expr.toString()); } } return result; @@ -1579,7 +1580,7 @@ public class FHIRPathEngine { return makeBoolean(res); } - private List opNotEquals(List left, List right) { + private List opNotEquals(List left, List right, ExpressionNode expr) { if (!legacyMode && (left.size() == 0 || right.size() == 0)) return new ArrayList(); @@ -1648,9 +1649,9 @@ public class FHIRPathEngine { } - private boolean doEquivalent(Base left, Base right) throws PathEngineException { + private boolean doEquivalent(Base left, Base right, ExpressionNode expr) throws PathEngineException { if (left instanceof Quantity && right instanceof Quantity) - return qtyEquivalent((Quantity) left, (Quantity) right); + return qtyEquivalent((Quantity) left, (Quantity) right, expr); if (left.hasType("integer") && right.hasType("integer")) return doEquals(left, right); if (left.hasType("boolean") && right.hasType("boolean")) @@ -1662,7 +1663,7 @@ public class FHIRPathEngine { if (left.hasType(FHIR_TYPES_STRING) && right.hasType(FHIR_TYPES_STRING)) return Utilities.equivalent(convertToString(left), convertToString(right)); - throw new PathEngineException(String.format("Unable to determine equivalence between %s and %s", left.fhirType(), right.fhirType())); + throw new PathEngineException(String.format("Unable to determine equivalence between %s and %s", left.fhirType(), right.fhirType()), expr.getStart(), expr.toString()); } private boolean qtyEqual(Quantity left, Quantity right) { @@ -1703,19 +1704,19 @@ public class FHIRPathEngine { } - private boolean qtyEquivalent(Quantity left, Quantity right) throws PathEngineException { + private boolean qtyEquivalent(Quantity left, Quantity right, ExpressionNode expr) throws PathEngineException { if (worker.getUcumService() != null) { DecimalType dl = qtyToCanonical(left); DecimalType dr = qtyToCanonical(right); if (dl != null && dr != null) - return doEquivalent(dl, dr); + return doEquivalent(dl, dr, expr); } return left.equals(right); } - private List opEquivalent(List left, List right) throws PathEngineException { + private List opEquivalent(List left, List right, ExpressionNode expr) throws PathEngineException { if (left.size() != right.size()) return makeBoolean(false); @@ -1723,7 +1724,7 @@ public class FHIRPathEngine { for (int i = 0; i < left.size(); i++) { boolean found = false; for (int j = 0; j < right.size(); j++) { - if (doEquivalent(left.get(i), right.get(j))) { + if (doEquivalent(left.get(i), right.get(j), expr)) { found = true; break; } @@ -1736,7 +1737,7 @@ public class FHIRPathEngine { return makeBoolean(res); } - private List opNotEquivalent(List left, List right) throws PathEngineException { + private List opNotEquivalent(List left, List right, ExpressionNode expr) throws PathEngineException { if (left.size() != right.size()) return makeBoolean(true); @@ -1744,7 +1745,7 @@ public class FHIRPathEngine { for (int i = 0; i < left.size(); i++) { boolean found = false; for (int j = 0; j < right.size(); j++) { - if (doEquivalent(left.get(i), right.get(j))) { + if (doEquivalent(left.get(i), right.get(j), expr)) { found = true; break; } @@ -1759,7 +1760,7 @@ public class FHIRPathEngine { private final static String[] FHIR_TYPES_STRING = new String[] {"string", "uri", "code", "oid", "id", "uuid", "sid", "markdown", "base64Binary", "canonical", "url"}; - private List opLessThan(List left, List right) throws FHIRException { + private List opLessThan(List left, List right, ExpressionNode expr) throws FHIRException { if (left.size() == 0 || right.size() == 0) return new ArrayList(); @@ -1775,12 +1776,12 @@ public class FHIRPathEngine { else if ((l.hasType("time")) && (r.hasType("time"))) return makeBoolean(l.primitiveValue().compareTo(r.primitiveValue()) < 0); else - throw new PathEngineException("Unable to compare values of type "+l.fhirType()+" and "+r.fhirType()); + throw new PathEngineException("Unable to compare values of type "+l.fhirType()+" and "+r.fhirType(), expr.getStart(), expr.toString()); } else if (left.size() == 1 && right.size() == 1 && left.get(0).fhirType().equals("Quantity") && right.get(0).fhirType().equals("Quantity") ) { List lUnit = left.get(0).listChildrenByName("code"); List rUnit = right.get(0).listChildrenByName("code"); if (Base.compareDeep(lUnit, rUnit, true)) { - return opLessThan(left.get(0).listChildrenByName("value"), right.get(0).listChildrenByName("value")); + return opLessThan(left.get(0).listChildrenByName("value"), right.get(0).listChildrenByName("value"), expr); } else { if (worker.getUcumService() == null) return makeBoolean(false); @@ -1789,14 +1790,14 @@ public class FHIRPathEngine { dl.add(qtyToCanonical((Quantity) left.get(0))); List dr = new ArrayList(); dr.add(qtyToCanonical((Quantity) right.get(0))); - return opLessThan(dl, dr); + return opLessThan(dl, dr, expr); } } } return new ArrayList(); } - private List opGreater(List left, List right) throws FHIRException { + private List opGreater(List left, List right, ExpressionNode expr) throws FHIRException { if (left.size() == 0 || right.size() == 0) return new ArrayList(); if (left.size() == 1 && right.size() == 1 && left.get(0).isPrimitive() && right.get(0).isPrimitive()) { @@ -1811,12 +1812,12 @@ public class FHIRPathEngine { else if ((l.hasType("time")) && (r.hasType("time"))) return makeBoolean(l.primitiveValue().compareTo(r.primitiveValue()) > 0); else - throw new PathEngineException("Unable to compare values of type "+l.fhirType()+" and "+r.fhirType()); + throw new PathEngineException("Unable to compare values of type "+l.fhirType()+" and "+r.fhirType(), expr.getStart(), expr.toString()); } else if (left.size() == 1 && right.size() == 1 && left.get(0).fhirType().equals("Quantity") && right.get(0).fhirType().equals("Quantity") ) { List lUnit = left.get(0).listChildrenByName("unit"); List rUnit = right.get(0).listChildrenByName("unit"); if (Base.compareDeep(lUnit, rUnit, true)) { - return opGreater(left.get(0).listChildrenByName("value"), right.get(0).listChildrenByName("value")); + return opGreater(left.get(0).listChildrenByName("value"), right.get(0).listChildrenByName("value"), expr); } else { if (worker.getUcumService() == null) return makeBoolean(false); @@ -1825,14 +1826,14 @@ public class FHIRPathEngine { dl.add(qtyToCanonical((Quantity) left.get(0))); List dr = new ArrayList(); dr.add(qtyToCanonical((Quantity) right.get(0))); - return opGreater(dl, dr); + return opGreater(dl, dr, expr); } } } return new ArrayList(); } - private List opLessOrEqual(List left, List right) throws FHIRException { + private List opLessOrEqual(List left, List right, ExpressionNode expr) throws FHIRException { if (left.size() == 0 || right.size() == 0) return new ArrayList(); if (left.size() == 1 && right.size() == 1 && left.get(0).isPrimitive() && right.get(0).isPrimitive()) { @@ -1847,14 +1848,14 @@ public class FHIRPathEngine { else if ((l.hasType("time")) && (r.hasType("time"))) return makeBoolean(l.primitiveValue().compareTo(r.primitiveValue()) <= 0); else - throw new PathEngineException("Unable to compare values of type "+l.fhirType()+" and "+r.fhirType()); + throw new PathEngineException("Unable to compare values of type "+l.fhirType()+" and "+r.fhirType(), expr.getStart(), expr.toString()); } else if (left.size() == 1 && right.size() == 1 && left.get(0).fhirType().equals("Quantity") && right.get(0).fhirType().equals("Quantity") ) { List lUnits = left.get(0).listChildrenByName("unit"); String lunit = lUnits.size() == 1 ? lUnits.get(0).primitiveValue() : null; List rUnits = right.get(0).listChildrenByName("unit"); String runit = rUnits.size() == 1 ? rUnits.get(0).primitiveValue() : null; if ((lunit == null && runit == null) || lunit.equals(runit)) { - return opLessOrEqual(left.get(0).listChildrenByName("value"), right.get(0).listChildrenByName("value")); + return opLessOrEqual(left.get(0).listChildrenByName("value"), right.get(0).listChildrenByName("value"), expr); } else { if (worker.getUcumService() == null) return makeBoolean(false); @@ -1863,14 +1864,14 @@ public class FHIRPathEngine { dl.add(qtyToCanonical((Quantity) left.get(0))); List dr = new ArrayList(); dr.add(qtyToCanonical((Quantity) right.get(0))); - return opLessOrEqual(dl, dr); + return opLessOrEqual(dl, dr, expr); } } } return new ArrayList(); } - private List opGreaterOrEqual(List left, List right) throws FHIRException { + private List opGreaterOrEqual(List left, List right, ExpressionNode expr) throws FHIRException { if (left.size() == 0 || right.size() == 0) return new ArrayList(); if (left.size() == 1 && right.size() == 1 && left.get(0).isPrimitive() && right.get(0).isPrimitive()) { @@ -1885,12 +1886,12 @@ public class FHIRPathEngine { else if ((l.hasType("time")) && (r.hasType("time"))) return makeBoolean(l.primitiveValue().compareTo(r.primitiveValue()) >= 0); else - throw new PathEngineException("Unable to compare values of type "+l.fhirType()+" and "+r.fhirType()); + throw new PathEngineException("Unable to compare values of type "+l.fhirType()+" and "+r.fhirType(), expr.getStart(), expr.toString()); } else if (left.size() == 1 && right.size() == 1 && left.get(0).fhirType().equals("Quantity") && right.get(0).fhirType().equals("Quantity") ) { List lUnit = left.get(0).listChildrenByName("unit"); List rUnit = right.get(0).listChildrenByName("unit"); if (Base.compareDeep(lUnit, rUnit, true)) { - return opGreaterOrEqual(left.get(0).listChildrenByName("value"), right.get(0).listChildrenByName("value")); + return opGreaterOrEqual(left.get(0).listChildrenByName("value"), right.get(0).listChildrenByName("value"), expr); } else { if (worker.getUcumService() == null) return makeBoolean(false); @@ -1899,14 +1900,14 @@ public class FHIRPathEngine { dl.add(qtyToCanonical((Quantity) left.get(0))); List dr = new ArrayList(); dr.add(qtyToCanonical((Quantity) right.get(0))); - return opGreaterOrEqual(dl, dr); + return opGreaterOrEqual(dl, dr, expr); } } } return new ArrayList(); } - private List opMemberOf(ExecutionContext context, List left, List right) throws FHIRException { + private List opMemberOf(ExecutionContext context, List left, List right, ExpressionNode expr) throws FHIRException { boolean ans = false; ValueSet vs = hostServices != null ? hostServices.resolveValueSet(context.appInfo, right.get(0).primitiveValue()) : worker.fetchResource(ValueSet.class, right.get(0).primitiveValue()); if (vs != null) { @@ -1926,7 +1927,7 @@ public class FHIRPathEngine { return makeBoolean(ans); } - private List opIn(List left, List right) throws FHIRException { + private List opIn(List left, List right, ExpressionNode expr) throws FHIRException { if (left.size() == 0) return new ArrayList(); if (right.size() == 0) @@ -1949,7 +1950,7 @@ public class FHIRPathEngine { return makeBoolean(ans); } - private List opContains(List left, List right) { + private List opContains(List left, List right, ExpressionNode expr) { if (left.size() == 0 || right.size() == 0) return new ArrayList(); boolean ans = true; @@ -1970,17 +1971,17 @@ public class FHIRPathEngine { return makeBoolean(ans); } - private List opPlus(List left, List right) throws PathEngineException { + private List opPlus(List left, List right, ExpressionNode expr) throws PathEngineException { if (left.size() == 0 || right.size() == 0) return new ArrayList(); if (left.size() > 1) - throw new PathEngineException("Error performing +: left operand has more than one value"); + throw new PathEngineException("Error performing +: left operand has more than one value", expr.getStart(), expr.toString()); if (!left.get(0).isPrimitive()) - throw new PathEngineException(String.format("Error performing +: left operand has the wrong type (%s)", left.get(0).fhirType())); + throw new PathEngineException(String.format("Error performing +: left operand has the wrong type (%s)", left.get(0).fhirType()), expr.getStart(), expr.toString()); if (right.size() > 1) - throw new PathEngineException("Error performing +: right operand has more than one value"); + throw new PathEngineException("Error performing +: right operand has more than one value", expr.getStart(), expr.toString()); if (!right.get(0).isPrimitive() && !((left.get(0).isDateTime() || "0".equals(left.get(0).primitiveValue()) || left.get(0).hasType("Quantity")) && right.get(0).hasType("Quantity"))) - throw new PathEngineException(String.format("Error performing +: right operand has the wrong type (%s)", right.get(0).fhirType())); + throw new PathEngineException(String.format("Error performing +: right operand has the wrong type (%s)", right.get(0).fhirType()), expr.getStart(), expr.toString()); List result = new ArrayList(); Base l = left.get(0); @@ -1992,13 +1993,13 @@ public class FHIRPathEngine { else if (l.hasType("decimal", "integer") && r.hasType("decimal", "integer")) result.add(new DecimalType(new BigDecimal(l.primitiveValue()).add(new BigDecimal(r.primitiveValue())))); else if (l.isDateTime() && r.hasType("Quantity")) - result.add(dateAdd((BaseDateTimeType) l, (Quantity) r, false)); + result.add(dateAdd((BaseDateTimeType) l, (Quantity) r, false, expr)); else - throw new PathEngineException(String.format("Error performing +: left and right operand have incompatible or illegal types (%s, %s)", left.get(0).fhirType(), right.get(0).fhirType())); + throw new PathEngineException(String.format("Error performing +: left and right operand have incompatible or illegal types (%s, %s)", left.get(0).fhirType(), right.get(0).fhirType()), expr.getStart(), expr.toString()); return result; } - private BaseDateTimeType dateAdd(BaseDateTimeType d, Quantity q, boolean negate) { + private BaseDateTimeType dateAdd(BaseDateTimeType d, Quantity q, boolean negate, ExpressionNode expr) { BaseDateTimeType result = (BaseDateTimeType) d.copy(); int value = negate ? 0 - q.getValue().intValue() : q.getValue().intValue(); @@ -2008,13 +2009,13 @@ public class FHIRPathEngine { result.add(Calendar.YEAR, value); break; case "a": - throw new PathEngineException(String.format("Error in date arithmetic: attempt to add a definite quantity duration time unit %s", q.getCode())); + throw new PathEngineException(String.format("Error in date arithmetic: attempt to add a definite quantity duration time unit %s", q.getCode()), expr.getStart(), expr.toString()); case "months": case "month": result.add(Calendar.MONTH, value); break; case "mo": - throw new PathEngineException(String.format("Error in date arithmetic: attempt to add a definite quantity duration time unit %s", q.getCode())); + throw new PathEngineException(String.format("Error in date arithmetic: attempt to add a definite quantity duration time unit %s", q.getCode()), expr.getStart(), expr.toString()); case "weeks": case "week": case "wk": @@ -2046,23 +2047,23 @@ public class FHIRPathEngine { result.add(Calendar.MILLISECOND, value); break; default: - throw new PathEngineException(String.format("Error in date arithmetic: unrecognized time unit %s", q.getCode())); + throw new PathEngineException(String.format("Error in date arithmetic: unrecognized time unit %s", q.getCode()), expr.getStart(), expr.toString()); } return result; } - private List opTimes(List left, List right) throws PathEngineException { + private List opTimes(List left, List right, ExpressionNode expr) throws PathEngineException { if (left.size() == 0 || right.size() == 0) return new ArrayList(); if (left.size() > 1) - throw new PathEngineException("Error performing *: left operand has more than one value"); + throw new PathEngineException("Error performing *: left operand has more than one value", expr.getStart(), expr.toString()); if (!left.get(0).isPrimitive() && !(left.get(0) instanceof Quantity)) - throw new PathEngineException(String.format("Error performing +: left operand has the wrong type (%s)", left.get(0).fhirType())); + throw new PathEngineException(String.format("Error performing +: left operand has the wrong type (%s)", left.get(0).fhirType()), expr.getStart(), expr.toString()); if (right.size() > 1) - throw new PathEngineException("Error performing *: right operand has more than one value"); + throw new PathEngineException("Error performing *: right operand has more than one value", expr.getStart(), expr.toString()); if (!right.get(0).isPrimitive() && !(right.get(0) instanceof Quantity)) - throw new PathEngineException(String.format("Error performing *: right operand has the wrong type (%s)", right.get(0).fhirType())); + throw new PathEngineException(String.format("Error performing *: right operand has the wrong type (%s)", right.get(0).fhirType()), expr.getStart(), expr.toString()); List result = new ArrayList(); Base l = left.get(0); @@ -2080,23 +2081,23 @@ public class FHIRPathEngine { p = worker.getUcumService().multiply(pl, pr); result.add(pairToQty(p)); } catch (UcumException e) { - throw new PathEngineException(e.getMessage(), e); + throw new PathEngineException(e.getMessage(), expr.getOpStart(), expr.toString(), e); } } else - throw new PathEngineException(String.format("Error performing *: left and right operand have incompatible or illegal types (%s, %s)", left.get(0).fhirType(), right.get(0).fhirType())); + throw new PathEngineException(String.format("Error performing *: left and right operand have incompatible or illegal types (%s, %s)", left.get(0).fhirType(), right.get(0).fhirType()), expr.getStart(), expr.toString()); return result; } - private List opConcatenate(List left, List right) throws PathEngineException { + private List opConcatenate(List left, List right, ExpressionNode expr) throws PathEngineException { if (left.size() > 1) - throw new PathEngineException("Error performing &: left operand has more than one value"); + throw new PathEngineException("Error performing &: left operand has more than one value", expr.getStart(), expr.toString()); if (left.size() > 0 && !left.get(0).hasType(FHIR_TYPES_STRING)) - throw new PathEngineException(String.format("Error performing &: left operand has the wrong type (%s)", left.get(0).fhirType())); + throw new PathEngineException(String.format("Error performing &: left operand has the wrong type (%s)", left.get(0).fhirType()), expr.getStart(), expr.toString()); if (right.size() > 1) - throw new PathEngineException("Error performing &: right operand has more than one value"); + throw new PathEngineException("Error performing &: right operand has more than one value", expr.getStart(), expr.toString()); if (right.size() > 0 && !right.get(0).hasType(FHIR_TYPES_STRING)) - throw new PathEngineException(String.format("Error performing &: right operand has the wrong type (%s)", right.get(0).fhirType())); + throw new PathEngineException(String.format("Error performing &: right operand has the wrong type (%s)", right.get(0).fhirType()), expr.getStart(), expr.toString()); List result = new ArrayList(); String l = left.size() == 0 ? "" : left.get(0).primitiveValue(); @@ -2105,7 +2106,7 @@ public class FHIRPathEngine { return result; } - private List opUnion(List left, List right) { + private List opUnion(List left, List right, ExpressionNode expr) { List result = new ArrayList(); for (Base item : left) { if (!doContains(result, item)) @@ -2128,9 +2129,9 @@ public class FHIRPathEngine { } - private List opAnd(List left, List right) throws PathEngineException { - Equality l = asBool(left); - Equality r = asBool(right); + private List opAnd(List left, List right, ExpressionNode expr) throws PathEngineException { + Equality l = asBool(left, expr); + Equality r = asBool(right, expr); switch (l) { case False: return makeBoolean(false); case Null: @@ -2152,9 +2153,9 @@ public class FHIRPathEngine { return list.size() == 1 && list.get(0) instanceof BooleanType && ((BooleanType) list.get(0)).booleanValue() == b; } - private List opOr(List left, List right) throws PathEngineException { - Equality l = asBool(left); - Equality r = asBool(right); + private List opOr(List left, List right, ExpressionNode expr) throws PathEngineException { + Equality l = asBool(left, expr); + Equality r = asBool(right, expr); switch (l) { case True: return makeBoolean(true); case Null: @@ -2172,9 +2173,9 @@ public class FHIRPathEngine { return makeNull(); } - private List opXor(List left, List right) throws PathEngineException { - Equality l = asBool(left); - Equality r = asBool(right); + private List opXor(List left, List right, ExpressionNode expr) throws PathEngineException { + Equality l = asBool(left, expr); + Equality r = asBool(right, expr); switch (l) { case True: switch (r) { @@ -2194,13 +2195,13 @@ public class FHIRPathEngine { return makeNull(); } - private List opImplies(List left, List right) throws PathEngineException { - Equality eq = asBool(left); + private List opImplies(List left, List right, ExpressionNode expr) throws PathEngineException { + Equality eq = asBool(left, expr); if (eq == Equality.False) return makeBoolean(true); else if (right.size() == 0) return makeNull(); - else switch (asBool(right)) { + else switch (asBool(right, expr)) { case False: return eq == Equality.Null ? makeNull() : makeBoolean(false); case Null: return makeNull(); case True: return makeBoolean(true); @@ -2209,17 +2210,17 @@ public class FHIRPathEngine { } - private List opMinus(List left, List right) throws PathEngineException { + private List opMinus(List left, List right, ExpressionNode expr) throws PathEngineException { if (left.size() == 0 || right.size() == 0) return new ArrayList(); if (left.size() > 1) - throw new PathEngineException("Error performing -: left operand has more than one value"); + throw new PathEngineException("Error performing -: left operand has more than one value", expr.getStart(), expr.toString()); if (!left.get(0).isPrimitive()) - throw new PathEngineException(String.format("Error performing -: left operand has the wrong type (%s)", left.get(0).fhirType())); + throw new PathEngineException(String.format("Error performing -: left operand has the wrong type (%s)", left.get(0).fhirType()), expr.getStart(), expr.toString()); if (right.size() > 1) - throw new PathEngineException("Error performing -: right operand has more than one value"); + throw new PathEngineException("Error performing -: right operand has more than one value", expr.getStart(), expr.toString()); if (!right.get(0).isPrimitive() && !((left.get(0).isDateTime() || "0".equals(left.get(0).primitiveValue()) || left.get(0).hasType("Quantity")) && right.get(0).hasType("Quantity"))) - throw new PathEngineException(String.format("Error performing -: right operand has the wrong type (%s)", right.get(0).fhirType())); + throw new PathEngineException(String.format("Error performing -: right operand has the wrong type (%s)", right.get(0).fhirType()), expr.getStart(), expr.toString()); List result = new ArrayList(); Base l = left.get(0); @@ -2230,23 +2231,23 @@ public class FHIRPathEngine { else if (l.hasType("decimal", "integer") && r.hasType("decimal", "integer")) result.add(new DecimalType(new BigDecimal(l.primitiveValue()).subtract(new BigDecimal(r.primitiveValue())))); else if (l.isDateTime() && r.hasType("Quantity")) - result.add(dateAdd((BaseDateTimeType) l, (Quantity) r, true)); + result.add(dateAdd((BaseDateTimeType) l, (Quantity) r, true, expr)); else - throw new PathEngineException(String.format("Error performing -: left and right operand have incompatible or illegal types (%s, %s)", left.get(0).fhirType(), right.get(0).fhirType())); + throw new PathEngineException(String.format("Error performing -: left and right operand have incompatible or illegal types (%s, %s)", left.get(0).fhirType(), right.get(0).fhirType()), expr.getStart(), expr.toString()); return result; } - private List opDivideBy(List left, List right) throws PathEngineException { + private List opDivideBy(List left, List right, ExpressionNode expr) throws PathEngineException { if (left.size() == 0 || right.size() == 0) return new ArrayList(); if (left.size() > 1) - throw new PathEngineException("Error performing /: left operand has more than one value"); + throw new PathEngineException("Error performing /: left operand has more than one value", expr.getStart(), expr.toString()); if (!left.get(0).isPrimitive() && !(left.get(0) instanceof Quantity)) - throw new PathEngineException(String.format("Error performing -: left operand has the wrong type (%s)", left.get(0).fhirType())); + throw new PathEngineException(String.format("Error performing -: left operand has the wrong type (%s)", left.get(0).fhirType()), expr.getStart(), expr.toString()); if (right.size() > 1) throw new PathEngineException("Error performing /: right operand has more than one value"); if (!right.get(0).isPrimitive() && !(right.get(0) instanceof Quantity)) - throw new PathEngineException(String.format("Error performing /: right operand has the wrong type (%s)", right.get(0).fhirType())); + throw new PathEngineException(String.format("Error performing /: right operand has the wrong type (%s)", right.get(0).fhirType()), expr.getStart(), expr.toString()); List result = new ArrayList(); Base l = left.get(0); @@ -2269,24 +2270,24 @@ public class FHIRPathEngine { p = worker.getUcumService().multiply(pl, pr); result.add(pairToQty(p)); } catch (UcumException e) { - throw new PathEngineException(e.getMessage(), e); + throw new PathEngineException(e.getMessage(), expr.getOpStart(), expr.toString(), e); } } else - throw new PathEngineException(String.format("Error performing /: left and right operand have incompatible or illegal types (%s, %s)", left.get(0).fhirType(), right.get(0).fhirType())); + throw new PathEngineException(String.format("Error performing /: left and right operand have incompatible or illegal types (%s, %s)", left.get(0).fhirType(), right.get(0).fhirType()), expr.getStart(), expr.toString()); return result; } - private List opDiv(List left, List right) throws PathEngineException { + private List opDiv(List left, List right, ExpressionNode expr) throws PathEngineException { if (left.size() == 0 || right.size() == 0) return new ArrayList(); if (left.size() > 1) - throw new PathEngineException("Error performing div: left operand has more than one value"); + throw new PathEngineException("Error performing div: left operand has more than one value", expr.getStart(), expr.toString()); if (!left.get(0).isPrimitive() && !(left.get(0) instanceof Quantity)) - throw new PathEngineException(String.format("Error performing div: left operand has the wrong type (%s)", left.get(0).fhirType())); + throw new PathEngineException(String.format("Error performing div: left operand has the wrong type (%s)", left.get(0).fhirType()), expr.getStart(), expr.toString()); if (right.size() > 1) - throw new PathEngineException("Error performing div: right operand has more than one value"); + throw new PathEngineException("Error performing div: right operand has more than one value", expr.getStart(), expr.toString()); if (!right.get(0).isPrimitive() && !(right.get(0) instanceof Quantity)) - throw new PathEngineException(String.format("Error performing div: right operand has the wrong type (%s)", right.get(0).fhirType())); + throw new PathEngineException(String.format("Error performing div: right operand has the wrong type (%s)", right.get(0).fhirType()), expr.getStart(), expr.toString()); List result = new ArrayList(); Base l = left.get(0); @@ -2305,21 +2306,21 @@ public class FHIRPathEngine { } } else - throw new PathEngineException(String.format("Error performing div: left and right operand have incompatible or illegal types (%s, %s)", left.get(0).fhirType(), right.get(0).fhirType())); + throw new PathEngineException(String.format("Error performing div: left and right operand have incompatible or illegal types (%s, %s)", left.get(0).fhirType(), right.get(0).fhirType()), expr.getStart(), expr.toString()); return result; } - private List opMod(List left, List right) throws PathEngineException { + private List opMod(List left, List right, ExpressionNode expr) throws PathEngineException { if (left.size() == 0 || right.size() == 0) return new ArrayList(); if (left.size() > 1) - throw new PathEngineException("Error performing mod: left operand has more than one value"); + throw new PathEngineException("Error performing mod: left operand has more than one value", expr.getStart(), expr.toString()); if (!left.get(0).isPrimitive()) - throw new PathEngineException(String.format("Error performing mod: left operand has the wrong type (%s)", left.get(0).fhirType())); + throw new PathEngineException(String.format("Error performing mod: left operand has the wrong type (%s)", left.get(0).fhirType()), expr.getStart(), expr.toString()); if (right.size() > 1) - throw new PathEngineException("Error performing mod: right operand has more than one value"); + throw new PathEngineException("Error performing mod: right operand has more than one value", expr.getStart(), expr.toString()); if (!right.get(0).isPrimitive()) - throw new PathEngineException(String.format("Error performing mod: right operand has the wrong type (%s)", right.get(0).fhirType())); + throw new PathEngineException(String.format("Error performing mod: right operand has the wrong type (%s)", right.get(0).fhirType()), expr.getStart(), expr.toString()); List result = new ArrayList(); Base l = left.get(0); @@ -2338,12 +2339,12 @@ public class FHIRPathEngine { } } else - throw new PathEngineException(String.format("Error performing mod: left and right operand have incompatible or illegal types (%s, %s)", left.get(0).fhirType(), right.get(0).fhirType())); + throw new PathEngineException(String.format("Error performing mod: left and right operand have incompatible or illegal types (%s, %s)", left.get(0).fhirType(), right.get(0).fhirType()), expr.getStart(), expr.toString()); return result; } - private TypeDetails resolveConstantType(ExecutionTypeContext context, Base constant) throws PathEngineException { + private TypeDetails resolveConstantType(ExecutionTypeContext context, Base constant, ExpressionNode expr) throws PathEngineException { if (constant instanceof BooleanType) return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); else if (constant instanceof IntegerType) @@ -2353,12 +2354,12 @@ public class FHIRPathEngine { else if (constant instanceof Quantity) return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Quantity); else if (constant instanceof FHIRConstant) - return resolveConstantType(context, ((FHIRConstant) constant).getValue()); + return resolveConstantType(context, ((FHIRConstant) constant).getValue(), expr); else return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); } - private TypeDetails resolveConstantType(ExecutionTypeContext context, String s) throws PathEngineException { + private TypeDetails resolveConstantType(ExecutionTypeContext context, String s, ExpressionNode expr) throws PathEngineException { if (s.startsWith("@")) { if (s.startsWith("@T")) return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Time); @@ -2372,11 +2373,11 @@ public class FHIRPathEngine { return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); else if (s.equals("%resource")) { if (context.resource == null) - throw new PathEngineException("%resource cannot be used in this context"); + throw new PathEngineException("%resource cannot be used in this context", expr.getStart(), expr.toString()); return new TypeDetails(CollectionStatus.SINGLETON, context.resource); } else if (s.equals("%rootResource")) { if (context.resource == null) - throw new PathEngineException("%rootResource cannot be used in this context"); + throw new PathEngineException("%rootResource cannot be used in this context", expr.getStart(), expr.toString()); return new TypeDetails(CollectionStatus.SINGLETON, context.resource); } else if (s.equals("%context")) { return context.context; @@ -2391,7 +2392,7 @@ public class FHIRPathEngine { else if (s.startsWith("%`ext-")) return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); else if (hostServices == null) - throw new PathEngineException("Unknown fixed constant type for '"+s+"'"); + throw new PathEngineException("Unknown fixed constant type for '"+s+"'", expr.getStart(), expr.toString()); else return hostServices.resolveConstantType(context.appInfo, s); } @@ -2422,9 +2423,9 @@ public class FHIRPathEngine { return result; } - private TypeDetails executeContextType(ExecutionTypeContext context, String name) throws PathEngineException, DefinitionException { + private TypeDetails executeContextType(ExecutionTypeContext context, String name, ExpressionNode expr) throws PathEngineException, DefinitionException { if (hostServices == null) - throw new PathEngineException("Unable to resolve context reference since no host services are provided"); + throw new PathEngineException("Unable to resolve context reference since no host services are provided", expr.getStart(), expr.toString()); return hostServices.resolveConstantType(context.appInfo, name); } @@ -2432,7 +2433,7 @@ public class FHIRPathEngine { if (atEntry && Character.isUpperCase(exp.getName().charAt(0)) && hashTail(type).equals(exp.getName())) // special case for start up return new TypeDetails(CollectionStatus.SINGLETON, type); TypeDetails result = new TypeDetails(null); - getChildTypesByName(type, exp.getName(), result); + getChildTypesByName(type, exp.getName(), result, exp); return result; } @@ -2462,11 +2463,11 @@ public class FHIRPathEngine { case Exists : return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); case SubsetOf : { - checkParamTypes(exp.getFunction().toCode(), paramTypes, focus); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, focus); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case SupersetOf : { - checkParamTypes(exp.getFunction().toCode(), paramTypes, focus); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, focus); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case IsDistinct : @@ -2486,16 +2487,16 @@ public class FHIRPathEngine { case Aggregate : return anything(focus.getCollectionStatus()); case Item : { - checkOrdered(focus, "item"); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer)); + checkOrdered(focus, "item", exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer)); return focus; } case As : { - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, exp.getParameters().get(0).getName()); } case OfType : { - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, exp.getParameters().get(0).getName()); } case Type : { @@ -2513,31 +2514,31 @@ public class FHIRPathEngine { return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_ClassInfo); } case Is : { - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case Single : return focus.toSingleton(); case First : { - checkOrdered(focus, "first"); + checkOrdered(focus, "first", exp); return focus.toSingleton(); } case Last : { - checkOrdered(focus, "last"); + checkOrdered(focus, "last", exp); return focus.toSingleton(); } case Tail : { - checkOrdered(focus, "tail"); + checkOrdered(focus, "tail", exp); return focus; } case Skip : { - checkOrdered(focus, "skip"); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer)); + checkOrdered(focus, "skip", exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer)); return focus; } case Take : { - checkOrdered(focus, "take"); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer)); + checkOrdered(focus, "take", exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer)); return focus; } case Union : { @@ -2560,76 +2561,76 @@ public class FHIRPathEngine { return types; } case Lower : { - checkContextString(focus, "lower"); + checkContextString(focus, "lower", exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); } case Upper : { - checkContextString(focus, "upper"); + checkContextString(focus, "upper", exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); } case ToChars : { - checkContextString(focus, "toChars"); + checkContextString(focus, "toChars", exp); return new TypeDetails(CollectionStatus.ORDERED, TypeDetails.FP_String); } case IndexOf : { - checkContextString(focus, "indexOf"); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkContextString(focus, "indexOf", exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer); } case Substring : { - checkContextString(focus, "subString"); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer), new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer)); + checkContextString(focus, "subString", exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer), new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); } case StartsWith : { - checkContextString(focus, "startsWith"); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkContextString(focus, "startsWith", exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case EndsWith : { - checkContextString(focus, "endsWith"); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkContextString(focus, "endsWith", exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case Matches : { - checkContextString(focus, "matches"); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkContextString(focus, "matches", exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case ReplaceMatches : { - checkContextString(focus, "replaceMatches"); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String), new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkContextString(focus, "replaceMatches", exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String), new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); } case Contains : { - checkContextString(focus, "contains"); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkContextString(focus, "contains", exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case Replace : { - checkContextString(focus, "replace"); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, "string"), new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkContextString(focus, "replace", exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, "string"), new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); } case Length : { - checkContextPrimitive(focus, "length", false); + checkContextPrimitive(focus, "length", false, exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer); } case Children : - return childTypes(focus, "*"); + return childTypes(focus, "*", exp); case Descendants : - return childTypes(focus, "**"); + return childTypes(focus, "**", exp); case MemberOf : { - checkContextCoded(focus, "memberOf"); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkContextCoded(focus, "memberOf", exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case Trace : { - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return focus; } case Check : { - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return focus; } case Today : @@ -2637,11 +2638,11 @@ public class FHIRPathEngine { case Now : return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_DateTime); case Resolve : { - checkContextReference(focus, "resolve"); + checkContextReference(focus, "resolve", exp); return new TypeDetails(CollectionStatus.SINGLETON, "DomainResource"); } case Extension : { - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, "Extension"); } case AnyTrue: @@ -2657,42 +2658,42 @@ public class FHIRPathEngine { case HtmlChecks : return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); case Alias : - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return anything(CollectionStatus.SINGLETON); case AliasAs : - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return focus; case ToInteger : { - checkContextPrimitive(focus, "toInteger", true); + checkContextPrimitive(focus, "toInteger", true, exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer); } case ToDecimal : { - checkContextPrimitive(focus, "toDecimal", true); + checkContextPrimitive(focus, "toDecimal", true, exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Decimal); } case ToString : { - checkContextPrimitive(focus, "toString", true); + checkContextPrimitive(focus, "toString", true, exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); } case ToQuantity : { - checkContextPrimitive(focus, "toQuantity", true); + checkContextPrimitive(focus, "toQuantity", true, exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Quantity); } case ToBoolean : { - checkContextPrimitive(focus, "toBoolean", false); + checkContextPrimitive(focus, "toBoolean", false, exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case ToDateTime : { - checkContextPrimitive(focus, "toBoolean", false); + checkContextPrimitive(focus, "toBoolean", false, exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_DateTime); } case ToTime : { - checkContextPrimitive(focus, "toBoolean", false); + checkContextPrimitive(focus, "toBoolean", false, exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Time); } case ConvertsToString : case ConvertsToQuantity :{ - checkContextPrimitive(focus, exp.getFunction().toCode(), true); + checkContextPrimitive(focus, exp.getFunction().toCode(), true, exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case ConvertsToInteger : @@ -2700,11 +2701,11 @@ public class FHIRPathEngine { case ConvertsToDateTime : case ConvertsToTime : case ConvertsToBoolean : { - checkContextPrimitive(focus, exp.getFunction().toCode(), false); + checkContextPrimitive(focus, exp.getFunction().toCode(), false, exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case ConformsTo: { - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case Custom : { @@ -2717,7 +2718,7 @@ public class FHIRPathEngine { } - private void checkParamTypes(String funcName, List paramTypes, TypeDetails... typeSet) throws PathEngineException { + private void checkParamTypes(ExpressionNode expr, String funcName, List paramTypes, TypeDetails... typeSet) throws PathEngineException { int i = 0; for (TypeDetails pt : typeSet) { if (i == paramTypes.size()) @@ -2726,47 +2727,47 @@ public class FHIRPathEngine { i++; for (String a : actual.getTypes()) { if (!pt.hasType(worker, a)) - throw new PathEngineException("The parameter type '"+a+"' is not legal for "+funcName+" parameter "+Integer.toString(i)+". expecting "+pt.toString()); + throw new PathEngineException("The parameter type '"+a+"' is not legal for "+funcName+" parameter "+Integer.toString(i)+". expecting "+pt.toString(), expr.getStart(), expr.toString()); } } } - private void checkOrdered(TypeDetails focus, String name) throws PathEngineException { + private void checkOrdered(TypeDetails focus, String name, ExpressionNode expr) throws PathEngineException { if (focus.getCollectionStatus() == CollectionStatus.UNORDERED) - throw new PathEngineException("The function '"+name+"'() can only be used on ordered collections"); + throw new PathEngineException("The function '"+name+"'() can only be used on ordered collections", expr.getStart(), expr.toString()); } - private void checkContextReference(TypeDetails focus, String name) throws PathEngineException { + private void checkContextReference(TypeDetails focus, String name, ExpressionNode expr) throws PathEngineException { if (!focus.hasType(worker, "string") && !focus.hasType(worker, "uri") && !focus.hasType(worker, "Reference") && !focus.hasType(worker, "canonical")) - throw new PathEngineException("The function '"+name+"'() can only be used on string, uri, canonical, Reference"); + throw new PathEngineException("The function '"+name+"'() can only be used on string, uri, canonical, Reference", expr.getStart(), expr.toString()); } - private void checkContextCoded(TypeDetails focus, String name) throws PathEngineException { + private void checkContextCoded(TypeDetails focus, String name, ExpressionNode expr) throws PathEngineException { if (!focus.hasType(worker, "string") && !focus.hasType(worker, "code") && !focus.hasType(worker, "uri") && !focus.hasType(worker, "Coding") && !focus.hasType(worker, "CodeableConcept")) - throw new PathEngineException("The function '"+name+"'() can only be used on string, code, uri, Coding, CodeableConcept"); + throw new PathEngineException("The function '"+name+"'() can only be used on string, code, uri, Coding, CodeableConcept", expr.getStart(), expr.toString()); } - private void checkContextString(TypeDetails focus, String name) throws PathEngineException { + private void checkContextString(TypeDetails focus, String name, ExpressionNode expr) throws PathEngineException { if (!focus.hasType(worker, "string") && !focus.hasType(worker, "code") && !focus.hasType(worker, "uri") && !focus.hasType(worker, "canonical") && !focus.hasType(worker, "id")) - throw new PathEngineException("The function '"+name+"'() can only be used on string, uri, code, id, but found "+focus.describe()); + throw new PathEngineException("The function '"+name+"'() can only be used on string, uri, code, id, but found "+focus.describe(), expr.getStart(), expr.toString()); } - private void checkContextPrimitive(TypeDetails focus, String name, boolean canQty) throws PathEngineException { + private void checkContextPrimitive(TypeDetails focus, String name, boolean canQty, ExpressionNode expr) throws PathEngineException { if (canQty) { if (!focus.hasType(primitiveTypes) && !focus.hasType("Quantity")) - throw new PathEngineException("The function '"+name+"'() can only be used on a Quantity or on "+primitiveTypes.toString()); + throw new PathEngineException("The function '"+name+"'() can only be used on a Quantity or on "+primitiveTypes.toString(), expr.getStart(), expr.toString()); } else if (!focus.hasType(primitiveTypes)) - throw new PathEngineException("The function '"+name+"'() can only be used on "+primitiveTypes.toString()); + throw new PathEngineException("The function '"+name+"'() can only be used on "+primitiveTypes.toString(), expr.getStart(), expr.toString()); } - private TypeDetails childTypes(TypeDetails focus, String mask) throws PathEngineException, DefinitionException { + private TypeDetails childTypes(TypeDetails focus, String mask, ExpressionNode expr) throws PathEngineException, DefinitionException { TypeDetails result = new TypeDetails(CollectionStatus.UNORDERED); for (String f : focus.getTypes()) - getChildTypesByName(f, mask, result); + getChildTypesByName(f, mask, result, expr); return result; } @@ -2895,7 +2896,7 @@ public class FHIRPathEngine { for (Base item : focus) { pc.clear(); pc.add(item); - Equality eq = asBool(execute(changeThis(context, item), pc, exp.getParameters().get(0), true)); + Equality eq = asBool(execute(changeThis(context, item), pc, exp.getParameters().get(0), true), exp); if (eq != Equality.True) { all = false; break; @@ -2990,15 +2991,15 @@ public class FHIRPathEngine { result.add(new StringType(n)); } else { - throw new PathEngineException(String.format("funcReplace() : checking for 2 arguments (pattern, substitution) but found %d items", exp.getParameters().size())); + throw new PathEngineException(String.format("funcReplace() : checking for 2 arguments (pattern, substitution) but found %d items", exp.getParameters().size()), exp.getStart(), exp.toString()); } } else { - throw new PathEngineException(String.format("funcReplace() : checking for 1 string item but found empty item")); + throw new PathEngineException(String.format("funcReplace() : checking for 1 string item but found empty item"), exp.getStart(), exp.toString()); } } else { - throw new PathEngineException(String.format("funcReplace() : checking for 1 string item but found %d items", focus.size())); + throw new PathEngineException(String.format("funcReplace() : checking for 1 string item but found %d items", focus.size()), exp.getStart(), exp.toString()); } return result; } @@ -3115,7 +3116,7 @@ public class FHIRPathEngine { private List funcIif(ExecutionContext context, List focus, ExpressionNode exp) throws FHIRException { List n1 = execute(context, focus, exp.getParameters().get(0), true); - Equality v = asBool(n1); + Equality v = asBool(n1, exp); if (v == Equality.True) return execute(context, focus, exp.getParameters().get(1), true); @@ -3187,7 +3188,7 @@ public class FHIRPathEngine { private List funcSingle(ExecutionContext context, List focus, ExpressionNode exp) throws PathEngineException { if (focus.size() == 1) return focus; - throw new PathEngineException(String.format("Single() : checking for 1 item but found %d items", focus.size())); + throw new PathEngineException(String.format("Single() : checking for 1 item but found %d items", focus.size()), exp.getStart(), exp.toString()); } @@ -3199,10 +3200,10 @@ public class FHIRPathEngine { ExpressionNode texp = exp.getParameters().get(0); if (texp.getKind() != Kind.Name) - throw new PathEngineException("Unsupported Expression type for Parameter on Is"); + throw new PathEngineException("Unsupported Expression type for Parameter on Is", exp.getStart(), exp.toString()); if (texp.getInner() != null) { if (texp.getInner().getKind() != Kind.Name) - throw new PathEngineException("Unsupported Expression type for Parameter on Is"); + throw new PathEngineException("Unsupported Expression type for Parameter on Is", exp.getStart(), exp.toString()); ns = texp.getName(); n = texp.getInner().getName(); } else if (Utilities.existsInList(texp.getName(), "Boolean", "Integer", "Decimal", "String", "DateTime", "Time", "SimpleTypeInfo", "ClassInfo")) { @@ -3447,7 +3448,7 @@ public class FHIRPathEngine { pc.clear(); pc.add(item); List res = execute(context, pc, exp.getParameters().get(0), true); - Equality v = asBool(res); + Equality v = asBool(res, exp); if (v != Equality.False) { all = false; break; @@ -3477,7 +3478,7 @@ public class FHIRPathEngine { pc.clear(); pc.add(item); List res = execute(context, pc, exp.getParameters().get(0), true); - Equality v = asBool(res); + Equality v = asBool(res, exp); if (v == Equality.False) { any = true; break; @@ -3507,7 +3508,7 @@ public class FHIRPathEngine { pc.clear(); pc.add(item); List res = execute(context, pc, exp.getParameters().get(0), true); - Equality v = asBool(res); + Equality v = asBool(res, exp); if (v != Equality.True) { all = false; break; @@ -3537,7 +3538,7 @@ public class FHIRPathEngine { pc.clear(); pc.add(item); List res = execute(context, pc, exp.getParameters().get(0), true); - Equality v = asBool(res); + Equality v = asBool(res, exp); if (v == Equality.True) { any = true; break; @@ -3961,7 +3962,7 @@ public class FHIRPathEngine { for (Base item : focus) { pc.clear(); pc.add(item); - Equality v = asBool(execute(changeThis(context, item), pc, exp.getParameters().get(0), true)); + Equality v = asBool(execute(changeThis(context, item), pc, exp.getParameters().get(0), true), exp); if (v == Equality.True) result.add(item); } @@ -3996,7 +3997,7 @@ public class FHIRPathEngine { private List funcNot(ExecutionContext context, List focus, ExpressionNode exp) throws PathEngineException { List result = new ArrayList(); - Equality v = asBool(focus); + Equality v = asBool(focus, exp); if (v != Equality.Null) result.add(new BooleanType(v != Equality.True)); return result; @@ -4019,9 +4020,9 @@ public class FHIRPathEngine { } - private void getChildTypesByName(String type, String name, TypeDetails result) throws PathEngineException, DefinitionException { + private void getChildTypesByName(String type, String name, TypeDetails result, ExpressionNode expr) throws PathEngineException, DefinitionException { if (Utilities.noString(type)) - throw new PathEngineException("No type provided in BuildToolPathEvaluator.getChildTypesByName"); + throw new PathEngineException("No type provided in BuildToolPathEvaluator.getChildTypesByName", expr.getStart(), expr.toString()); if (type.equals("http://hl7.org/fhir/StructureDefinition/xhtml")) return; if (type.startsWith(Constants.NS_SYSTEM_TYPE)) @@ -4045,7 +4046,7 @@ public class FHIRPathEngine { List sdl = new ArrayList(); ElementDefinitionMatch m = null; if (type.contains("#")) - m = getElementDefinition(sd, type.substring(type.indexOf("#")+1), false); + m = getElementDefinition(sd, type.substring(type.indexOf("#")+1), false, expr); if (m != null && hasDataType(m.definition)) { if (m.fixedType != null) { @@ -4084,11 +4085,11 @@ public class FHIRPathEngine { if (t.getCode().equals("Resource")) { for (String rn : worker.getResourceNames()) { if (!result.hasType(worker, rn)) { - getChildTypesByName(result.addType(rn), "**", result); + getChildTypesByName(result.addType(rn), "**", result, expr); } } } else if (!result.hasType(worker, tn)) { - getChildTypesByName(result.addType(tn), "**", result); + getChildTypesByName(result.addType(tn), "**", result, expr); } } } @@ -4111,7 +4112,7 @@ public class FHIRPathEngine { } else { path = sdi.getSnapshot().getElement().get(0).getPath()+tail+"."+name; - ElementDefinitionMatch ed = getElementDefinition(sdi, path, false); + ElementDefinitionMatch ed = getElementDefinition(sdi, path, false, expr); if (ed != null) { if (!Utilities.noString(ed.getFixedType())) result.addType(ed.getFixedType()); @@ -4160,7 +4161,7 @@ public class FHIRPathEngine { } - private ElementDefinitionMatch getElementDefinition(StructureDefinition sd, String path, boolean allowTypedName) throws PathEngineException { + private ElementDefinitionMatch getElementDefinition(StructureDefinition sd, String path, boolean allowTypedName, ExpressionNode expr) throws PathEngineException { for (ElementDefinition ed : sd.getSnapshot().getElement()) { if (ed.getPath().equals(path)) { if (ed.hasContentReference()) { @@ -4180,15 +4181,15 @@ public class FHIRPathEngine { if (ed.getPath().contains(".") && path.startsWith(ed.getPath()+".") && (ed.getType().size() > 0) && !isAbstractType(ed.getType())) { // now we walk into the type. if (ed.getType().size() > 1) // if there's more than one type, the test above would fail this - throw new PathEngineException("Internal typing issue...."); + throw new PathEngineException("Internal typing issue....", expr.getStart(), expr.toString()); StructureDefinition nsd = worker.fetchResource(StructureDefinition.class, ProfileUtilities.sdNs(ed.getType().get(0).getCode(), worker.getOverrideVersionNs())); if (nsd == null) - throw new PathEngineException("Unknown type "+ed.getType().get(0).getCode()); - return getElementDefinition(nsd, nsd.getId()+path.substring(ed.getPath().length()), allowTypedName); + throw new PathEngineException("Unknown type "+ed.getType().get(0).getCode(), expr.getStart(), expr.toString()); + return getElementDefinition(nsd, nsd.getId()+path.substring(ed.getPath().length()), allowTypedName, expr); } if (ed.hasContentReference() && path.startsWith(ed.getPath()+".")) { ElementDefinitionMatch m = getElementDefinitionById(sd, ed.getContentReference()); - return getElementDefinition(sd, m.definition.getPath()+path.substring(ed.getPath().length()), allowTypedName); + return getElementDefinition(sd, m.definition.getPath()+path.substring(ed.getPath().length()), allowTypedName, expr); } } return null; @@ -4363,13 +4364,13 @@ public class FHIRPathEngine { return path.substring(path.lastIndexOf(".") + 1); } - private Equality asBool(List items) throws PathEngineException { + private Equality asBool(List items, ExpressionNode expr) throws PathEngineException { if (items.size() == 0) return Equality.Null; else if (items.size() == 1) return asBool(items.get(0)); else - throw new PathEngineException("Unable to evaluate as a boolean: "+convertToString(items)); + throw new PathEngineException("Unable to evaluate as a boolean: "+convertToString(items), expr.getStart(), expr.toString()); } private Equality asBoolFromInt(String s) { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/ExpressionNode.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/ExpressionNode.java index 3ef89fd7b..253a39b65 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/ExpressionNode.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/ExpressionNode.java @@ -34,6 +34,7 @@ package org.hl7.fhir.r5.model; import java.util.ArrayList; import java.util.List; +import org.hl7.fhir.utilities.SourceLocation; import org.hl7.fhir.utilities.Utilities; public class ExpressionNode { @@ -41,31 +42,7 @@ public class ExpressionNode { public enum Kind { Name, Function, Constant, Group, Unary } - public static class SourceLocation { - private int line; - private int column; - public SourceLocation(int line, int column) { - super(); - this.line = line; - this.column = column; - } - public int getLine() { - return line; - } - public int getColumn() { - return column; - } - public void setLine(int line) { - this.line = line; - } - public void setColumn(int column) { - this.column = column; - } - public String toString() { - return Integer.toString(line)+", "+Integer.toString(column); - } - } public enum Function { Custom, diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRLexer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRLexer.java index e08acbefb..4400bcdc8 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRLexer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRLexer.java @@ -34,7 +34,7 @@ import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.r5.model.ExpressionNode; -import org.hl7.fhir.r5.model.ExpressionNode.SourceLocation; +import org.hl7.fhir.utilities.SourceLocation; import org.hl7.fhir.utilities.Utilities; // shared lexer for concrete syntaxes diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java index 6f6e4de68..334b8648f 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java @@ -39,7 +39,6 @@ import org.hl7.fhir.r5.model.ExpressionNode.CollectionStatus; import org.hl7.fhir.r5.model.ExpressionNode.Function; import org.hl7.fhir.r5.model.ExpressionNode.Kind; import org.hl7.fhir.r5.model.ExpressionNode.Operation; -import org.hl7.fhir.r5.model.ExpressionNode.SourceLocation; import org.hl7.fhir.r5.model.Property.PropertyMatcher; import org.hl7.fhir.r5.model.IntegerType; import org.hl7.fhir.r5.model.Property; @@ -59,6 +58,7 @@ import org.hl7.fhir.r5.utils.FHIRPathEngine.IEvaluationContext.FunctionDetails; import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; import org.hl7.fhir.utilities.MergedList; import org.hl7.fhir.utilities.MergedList.MergeNode; +import org.hl7.fhir.utilities.SourceLocation; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.i18n.I18nConstants; import org.hl7.fhir.utilities.validation.ValidationMessage; @@ -510,11 +510,11 @@ public class FHIRPathEngine { } StructureDefinition sd = worker.fetchResource(StructureDefinition.class, ctxt); if (sd == null) { - throw makeException(I18nConstants.FHIRPATH_UNKNOWN_CONTEXT, context); + throw makeException(expr, I18nConstants.FHIRPATH_UNKNOWN_CONTEXT, context); } - ElementDefinitionMatch ed = getElementDefinition(sd, context, true); + ElementDefinitionMatch ed = getElementDefinition(sd, context, true, expr); if (ed == null) { - throw makeException(I18nConstants.FHIRPATH_UNKNOWN_CONTEXT_ELEMENT, context); + throw makeException(expr, I18nConstants.FHIRPATH_UNKNOWN_CONTEXT_ELEMENT, context); } if (ed.fixedType != null) { types = new TypeDetails(CollectionStatus.SINGLETON, ed.fixedType); @@ -531,12 +531,16 @@ public class FHIRPathEngine { return executeType(new ExecutionTypeContext(appContext, resourceType, types, types), types, expr, true); } - private FHIRException makeException(String constName, Object... args) { + private FHIRException makeException(ExpressionNode holder, String constName, Object... args) { String fmt = worker.formatMessage(constName, args); if (location != null) { fmt = fmt + " "+worker.formatMessage(I18nConstants.FHIRPATH_LOCATION, location); } - return new PathEngineException(fmt); + if (holder != null) { + return new PathEngineException(fmt, holder.getStart(), holder.toString()); + } else { + return new PathEngineException(fmt); + } } public TypeDetails check(Object appContext, StructureDefinition sd, String context, ExpressionNode expr) throws FHIRLexerException, PathEngineException, DefinitionException { @@ -545,9 +549,9 @@ public class FHIRPathEngine { if (!context.contains(".")) { types = new TypeDetails(CollectionStatus.SINGLETON, sd.getUrl()); } else { - ElementDefinitionMatch ed = getElementDefinition(sd, context, true); + ElementDefinitionMatch ed = getElementDefinition(sd, context, true, expr); if (ed == null) { - throw makeException(I18nConstants.FHIRPATH_UNKNOWN_CONTEXT_ELEMENT, context); + throw makeException(expr, I18nConstants.FHIRPATH_UNKNOWN_CONTEXT_ELEMENT, context); } if (ed.fixedType != null) { types = new TypeDetails(CollectionStatus.SINGLETON, ed.fixedType); @@ -908,7 +912,7 @@ public class FHIRPathEngine { aliases = new HashMap(aliases); // clone it, since it's going to change } if (focus.size() > 1) { - throw makeException(I18nConstants.FHIRPATH_ALIAS_COLLECTION); + throw makeException(null, I18nConstants.FHIRPATH_ALIAS_COLLECTION); } aliases.put(name, focus.size() == 0 ? null : focus.get(0)); } @@ -957,6 +961,7 @@ public class FHIRPathEngine { wrapper = new ExpressionNode(lexer.nextId()); wrapper.setKind(Kind.Unary); wrapper.setOperation(ExpressionNode.Operation.fromCode(lexer.take())); + wrapper.setStart(lexer.getCurrentLocation()); wrapper.setProximal(proximal); } @@ -968,6 +973,7 @@ public class FHIRPathEngine { wrapper.setKind(Kind.Unary); wrapper.setOperation(ExpressionNode.Operation.fromCode(lexer.getCurrent().substring(0, 1))); wrapper.setProximal(proximal); + wrapper.setStart(lexer.getCurrentLocation()); lexer.setCurrent(lexer.getCurrent().substring(1)); } result.setConstant(processConstant(lexer)); @@ -1355,7 +1361,7 @@ public class FHIRPathEngine { work.addAll(work2); break; case Constant: - Base b = resolveConstant(context, exp.getConstant(), false); + Base b = resolveConstant(context, exp.getConstant(), false, exp); if (b != null) { work.add(b); } @@ -1373,16 +1379,16 @@ public class FHIRPathEngine { ExpressionNode next = exp.getOpNext(); ExpressionNode last = exp; while (next != null) { - List work2 = preOperate(work, last.getOperation()); + List work2 = preOperate(work, last.getOperation(), exp); if (work2 != null) { work = work2; } else if (last.getOperation() == Operation.Is || last.getOperation() == Operation.As) { work2 = executeTypeName(context, focus, next, false); - work = operate(context, work, last.getOperation(), work2); + work = operate(context, work, last.getOperation(), work2, last); } else { work2 = execute(context, focus, next, true); - work = operate(context, work, last.getOperation(), work2); + work = operate(context, work, last.getOperation(), work2, last); // System.out.println("Result of {'"+last.toString()+" "+last.getOperation().toCode()+" "+next.toString()+"'}: "+focus.toString()); } last = next; @@ -1404,7 +1410,7 @@ public class FHIRPathEngine { } - private List preOperate(List left, Operation operation) throws PathEngineException { + private List preOperate(List left, Operation operation, ExpressionNode expr) throws PathEngineException { if (left.size() == 0) { return null; } @@ -1414,7 +1420,7 @@ public class FHIRPathEngine { case Or: return isBoolean(left, true) ? makeBoolean(true) : null; case Implies: - Equality v = asBool(left); + Equality v = asBool(left, expr); return v == Equality.False ? makeBoolean(true) : null; default: return null; @@ -1445,13 +1451,13 @@ public class FHIRPathEngine { } else if (atEntry && exp.getName().equals("$total")) { result.update(anything(CollectionStatus.UNORDERED)); } else if (atEntry && focus == null) { - result.update(executeContextType(context, exp.getName())); + result.update(executeContextType(context, exp.getName(), exp)); } else { for (String s : focus.getTypes()) { result.update(executeType(s, exp, atEntry)); } if (result.hasNoTypes()) { - throw makeException(I18nConstants.FHIRPATH_UNKNOWN_NAME, exp.getName(), focus.describe()); + throw makeException(exp, I18nConstants.FHIRPATH_UNKNOWN_NAME, exp.getName(), focus.describe()); } } break; @@ -1464,7 +1470,7 @@ public class FHIRPathEngine { result.addType(TypeDetails.FP_Quantity); break; case Constant: - result.update(resolveConstantType(context, exp.getConstant())); + result.update(resolveConstantType(context, exp.getConstant(), exp)); break; case Group: result.update(executeType(context, focus, exp.getGroup(), atEntry)); @@ -1485,7 +1491,7 @@ public class FHIRPathEngine { } else { work = executeType(context, focus, next, atEntry); } - result = operateTypes(result, last.getOperation(), work); + result = operateTypes(result, last.getOperation(), work, last); last = next; next = next.getOpNext(); } @@ -1494,21 +1500,21 @@ public class FHIRPathEngine { return result; } - private Base resolveConstant(ExecutionContext context, Base constant, boolean beforeContext) throws PathEngineException { + private Base resolveConstant(ExecutionContext context, Base constant, boolean beforeContext, ExpressionNode expr) throws PathEngineException { if (!(constant instanceof FHIRConstant)) { return constant; } FHIRConstant c = (FHIRConstant) constant; if (c.getValue().startsWith("%")) { - return resolveConstant(context, c.getValue(), beforeContext); + return resolveConstant(context, c.getValue(), beforeContext, expr); } else if (c.getValue().startsWith("@")) { - return processDateConstant(context.appInfo, c.getValue().substring(1)); + return processDateConstant(context.appInfo, c.getValue().substring(1), expr); } else { - throw makeException(I18nConstants.FHIRPATH_UNKNOWN_CONSTANT, c.getValue()); + throw makeException(expr, I18nConstants.FHIRPATH_UNKNOWN_CONSTANT, c.getValue()); } } - private Base processDateConstant(Object appInfo, String value) throws PathEngineException { + private Base processDateConstant(Object appInfo, String value, ExpressionNode expr) throws PathEngineException { String date = null; String time = null; String tz = null; @@ -1556,7 +1562,7 @@ public class FHIRPathEngine { if (date == null) { if (tz != null) { - throw makeException(I18nConstants.FHIRPATH_UNKNOWN_CONTEXT, value); + throw makeException(expr, I18nConstants.FHIRPATH_UNKNOWN_CONTEXT, value); } else { TimeType tt = new TimeType(time); tt.setPrecision(temp); @@ -1572,7 +1578,7 @@ public class FHIRPathEngine { } - private Base resolveConstant(ExecutionContext context, String s, boolean beforeContext) throws PathEngineException { + private Base resolveConstant(ExecutionContext context, String s, boolean beforeContext, ExpressionNode expr) throws PathEngineException { if (s.equals("%sct")) { return new StringType("http://snomed.info/sct").noExtensions(); } else if (s.equals("%loinc")) { @@ -1581,12 +1587,12 @@ public class FHIRPathEngine { return new StringType("http://unitsofmeasure.org").noExtensions(); } else if (s.equals("%resource")) { if (context.focusResource == null) { - throw makeException(I18nConstants.FHIRPATH_CANNOT_USE, "%resource", "no focus resource"); + throw makeException(expr, I18nConstants.FHIRPATH_CANNOT_USE, "%resource", "no focus resource"); } return context.focusResource; } else if (s.equals("%rootResource")) { if (context.rootResource == null) { - throw makeException(I18nConstants.FHIRPATH_CANNOT_USE, "%rootResource", "no focus resource"); + throw makeException(expr, I18nConstants.FHIRPATH_CANNOT_USE, "%rootResource", "no focus resource"); } return context.rootResource; } else if (s.equals("%context")) { @@ -1600,7 +1606,7 @@ public class FHIRPathEngine { } else if (s.startsWith("%`ext-")) { return new StringType("http://hl7.org/fhir/StructureDefinition/"+s.substring(6, s.length()-1)).noExtensions(); } else if (hostServices == null) { - throw makeException(I18nConstants.FHIRPATH_UNKNOWN_CONSTANT, s); + throw makeException(expr, I18nConstants.FHIRPATH_UNKNOWN_CONSTANT, s); } else { return hostServices.resolveConstant(context.appInfo, s.substring(1), beforeContext); } @@ -1661,39 +1667,39 @@ public class FHIRPathEngine { } - private List operate(ExecutionContext context, List left, Operation operation, List right) throws FHIRException { + private List operate(ExecutionContext context, List left, Operation operation, List right, ExpressionNode holder) throws FHIRException { switch (operation) { - case Equals: return opEquals(left, right); - case Equivalent: return opEquivalent(left, right); - case NotEquals: return opNotEquals(left, right); - case NotEquivalent: return opNotEquivalent(left, right); - case LessThan: return opLessThan(left, right); - case Greater: return opGreater(left, right); - case LessOrEqual: return opLessOrEqual(left, right); - case GreaterOrEqual: return opGreaterOrEqual(left, right); - case Union: return opUnion(left, right); - case In: return opIn(left, right); - case MemberOf: return opMemberOf(context, left, right); - case Contains: return opContains(left, right); - case Or: return opOr(left, right); - case And: return opAnd(left, right); - case Xor: return opXor(left, right); - case Implies: return opImplies(left, right); - case Plus: return opPlus(left, right); - case Times: return opTimes(left, right); - case Minus: return opMinus(left, right); - case Concatenate: return opConcatenate(left, right); - case DivideBy: return opDivideBy(left, right); - case Div: return opDiv(left, right); - case Mod: return opMod(left, right); - case Is: return opIs(left, right); - case As: return opAs(left, right); + case Equals: return opEquals(left, right, holder); + case Equivalent: return opEquivalent(left, right, holder); + case NotEquals: return opNotEquals(left, right, holder); + case NotEquivalent: return opNotEquivalent(left, right, holder); + case LessThan: return opLessThan(left, right, holder); + case Greater: return opGreater(left, right, holder); + case LessOrEqual: return opLessOrEqual(left, right, holder); + case GreaterOrEqual: return opGreaterOrEqual(left, right, holder); + case Union: return opUnion(left, right, holder); + case In: return opIn(left, right, holder); + case MemberOf: return opMemberOf(context, left, right, holder); + case Contains: return opContains(left, right, holder); + case Or: return opOr(left, right, holder); + case And: return opAnd(left, right, holder); + case Xor: return opXor(left, right, holder); + case Implies: return opImplies(left, right, holder); + case Plus: return opPlus(left, right, holder); + case Times: return opTimes(left, right, holder); + case Minus: return opMinus(left, right, holder); + case Concatenate: return opConcatenate(left, right, holder); + case DivideBy: return opDivideBy(left, right, holder); + case Div: return opDiv(left, right, holder); + case Mod: return opMod(left, right, holder); + case Is: return opIs(left, right, holder); + case As: return opAs(left, right, holder); default: throw new Error("Not Done Yet: "+operation.toCode()); } } - private List opAs(List left, List right) { + private List opAs(List left, List right, ExpressionNode expr) { List result = new ArrayList<>(); if (right.size() != 1) { return result; @@ -1709,7 +1715,7 @@ public class FHIRPathEngine { } - private List opIs(List left, List right) { + private List opIs(List left, List right, ExpressionNode expr) { List result = new ArrayList(); if (left.size() == 0 || right.size() == 0) { } else if (left.size() != 1 || right.size() != 1) @@ -1728,7 +1734,7 @@ public class FHIRPathEngine { } - private TypeDetails operateTypes(TypeDetails left, Operation operation, TypeDetails right) { + private TypeDetails operateTypes(TypeDetails left, Operation operation, TypeDetails right, ExpressionNode expr) { switch (operation) { case Equals: return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); case Equivalent: return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); @@ -1776,7 +1782,7 @@ public class FHIRPathEngine { if (right.hasType(worker, "Quantity")) { result.addType(left.getType()); } else { - throw new PathEngineException(String.format("Error in date arithmetic: Unable to add type {0} to {1}", right.getType(), left.getType())); + throw new PathEngineException(String.format("Error in date arithmetic: Unable to add type {0} to {1}", right.getType(), left.getType()), expr.getOpStart(), expr.toString()); } } return result; @@ -1814,7 +1820,7 @@ public class FHIRPathEngine { } - private List opEquals(List left, List right) { + private List opEquals(List left, List right, ExpressionNode expr) { if (left.size() == 0 || right.size() == 0) { return new ArrayList(); } @@ -1843,7 +1849,7 @@ public class FHIRPathEngine { } } - private List opNotEquals(List left, List right) { + private List opNotEquals(List left, List right, ExpressionNode expr) { if (!legacyMode && (left.size() == 0 || right.size() == 0)) { return new ArrayList(); } @@ -2074,7 +2080,7 @@ public class FHIRPathEngine { - private List opEquivalent(List left, List right) throws PathEngineException { + private List opEquivalent(List left, List right, ExpressionNode expr) throws PathEngineException { if (left.size() != right.size()) { return makeBoolean(false); } @@ -2096,7 +2102,7 @@ public class FHIRPathEngine { return makeBoolean(res); } - private List opNotEquivalent(List left, List right) throws PathEngineException { + private List opNotEquivalent(List left, List right, ExpressionNode expr) throws PathEngineException { if (left.size() != right.size()) { return makeBoolean(true); } @@ -2120,7 +2126,7 @@ public class FHIRPathEngine { private final static String[] FHIR_TYPES_STRING = new String[] {"string", "uri", "code", "oid", "id", "uuid", "sid", "markdown", "base64Binary", "canonical", "url"}; - private List opLessThan(List left, List right) throws FHIRException { + private List opLessThan(List left, List right, ExpressionNode expr) throws FHIRException { if (left.size() == 0 || right.size() == 0) return new ArrayList(); @@ -2146,13 +2152,13 @@ public class FHIRPathEngine { return makeBoolean(i < 0); } } else { - throw makeException(I18nConstants.FHIRPATH_CANT_COMPARE, l.fhirType(), r.fhirType()); + throw makeException(expr, I18nConstants.FHIRPATH_CANT_COMPARE, l.fhirType(), r.fhirType()); } } else if (left.size() == 1 && right.size() == 1 && left.get(0).fhirType().equals("Quantity") && right.get(0).fhirType().equals("Quantity") ) { List lUnit = left.get(0).listChildrenByName("code"); List rUnit = right.get(0).listChildrenByName("code"); if (Base.compareDeep(lUnit, rUnit, true)) { - return opLessThan(left.get(0).listChildrenByName("value"), right.get(0).listChildrenByName("value")); + return opLessThan(left.get(0).listChildrenByName("value"), right.get(0).listChildrenByName("value"), expr); } else { if (worker.getUcumService() == null) { return makeBoolean(false); @@ -2161,14 +2167,14 @@ public class FHIRPathEngine { dl.add(qtyToCanonicalDecimal((Quantity) left.get(0))); List dr = new ArrayList(); dr.add(qtyToCanonicalDecimal((Quantity) right.get(0))); - return opLessThan(dl, dr); + return opLessThan(dl, dr, expr); } } } return new ArrayList(); } - private List opGreater(List left, List right) throws FHIRException { + private List opGreater(List left, List right, ExpressionNode expr) throws FHIRException { if (left.size() == 0 || right.size() == 0) return new ArrayList(); if (left.size() == 1 && right.size() == 1 && left.get(0).isPrimitive() && right.get(0).isPrimitive()) { @@ -2193,13 +2199,13 @@ public class FHIRPathEngine { return makeBoolean(i > 0); } } else { - throw makeException(I18nConstants.FHIRPATH_CANT_COMPARE, l.fhirType(), r.fhirType()); + throw makeException(expr, I18nConstants.FHIRPATH_CANT_COMPARE, l.fhirType(), r.fhirType()); } } else if (left.size() == 1 && right.size() == 1 && left.get(0).fhirType().equals("Quantity") && right.get(0).fhirType().equals("Quantity") ) { List lUnit = left.get(0).listChildrenByName("unit"); List rUnit = right.get(0).listChildrenByName("unit"); if (Base.compareDeep(lUnit, rUnit, true)) { - return opGreater(left.get(0).listChildrenByName("value"), right.get(0).listChildrenByName("value")); + return opGreater(left.get(0).listChildrenByName("value"), right.get(0).listChildrenByName("value"), expr); } else { if (worker.getUcumService() == null) { return makeBoolean(false); @@ -2208,14 +2214,14 @@ public class FHIRPathEngine { dl.add(qtyToCanonicalDecimal((Quantity) left.get(0))); List dr = new ArrayList(); dr.add(qtyToCanonicalDecimal((Quantity) right.get(0))); - return opGreater(dl, dr); + return opGreater(dl, dr, expr); } } } return new ArrayList(); } - private List opLessOrEqual(List left, List right) throws FHIRException { + private List opLessOrEqual(List left, List right, ExpressionNode expr) throws FHIRException { if (left.size() == 0 || right.size() == 0) { return new ArrayList(); } @@ -2241,7 +2247,7 @@ public class FHIRPathEngine { return makeBoolean(i <= 0); } } else { - throw makeException(I18nConstants.FHIRPATH_CANT_COMPARE, l.fhirType(), r.fhirType()); + throw makeException(expr, I18nConstants.FHIRPATH_CANT_COMPARE, l.fhirType(), r.fhirType()); } } else if (left.size() == 1 && right.size() == 1 && left.get(0).fhirType().equals("Quantity") && right.get(0).fhirType().equals("Quantity") ) { List lUnits = left.get(0).listChildrenByName("unit"); @@ -2249,7 +2255,7 @@ public class FHIRPathEngine { List rUnits = right.get(0).listChildrenByName("unit"); String runit = rUnits.size() == 1 ? rUnits.get(0).primitiveValue() : null; if ((lunit == null && runit == null) || lunit.equals(runit)) { - return opLessOrEqual(left.get(0).listChildrenByName("value"), right.get(0).listChildrenByName("value")); + return opLessOrEqual(left.get(0).listChildrenByName("value"), right.get(0).listChildrenByName("value"), expr); } else { if (worker.getUcumService() == null) { return makeBoolean(false); @@ -2258,14 +2264,14 @@ public class FHIRPathEngine { dl.add(qtyToCanonicalDecimal((Quantity) left.get(0))); List dr = new ArrayList(); dr.add(qtyToCanonicalDecimal((Quantity) right.get(0))); - return opLessOrEqual(dl, dr); + return opLessOrEqual(dl, dr, expr); } } } return new ArrayList(); } - private List opGreaterOrEqual(List left, List right) throws FHIRException { + private List opGreaterOrEqual(List left, List right, ExpressionNode expr) throws FHIRException { if (left.size() == 0 || right.size() == 0) { return new ArrayList(); } @@ -2291,13 +2297,13 @@ public class FHIRPathEngine { return makeBoolean(i >= 0); } } else { - throw makeException(I18nConstants.FHIRPATH_CANT_COMPARE, l.fhirType(), r.fhirType()); + throw makeException(expr, I18nConstants.FHIRPATH_CANT_COMPARE, l.fhirType(), r.fhirType()); } } else if (left.size() == 1 && right.size() == 1 && left.get(0).fhirType().equals("Quantity") && right.get(0).fhirType().equals("Quantity") ) { List lUnit = left.get(0).listChildrenByName("unit"); List rUnit = right.get(0).listChildrenByName("unit"); if (Base.compareDeep(lUnit, rUnit, true)) { - return opGreaterOrEqual(left.get(0).listChildrenByName("value"), right.get(0).listChildrenByName("value")); + return opGreaterOrEqual(left.get(0).listChildrenByName("value"), right.get(0).listChildrenByName("value"), expr); } else { if (worker.getUcumService() == null) { return makeBoolean(false); @@ -2306,14 +2312,14 @@ public class FHIRPathEngine { dl.add(qtyToCanonicalDecimal((Quantity) left.get(0))); List dr = new ArrayList(); dr.add(qtyToCanonicalDecimal((Quantity) right.get(0))); - return opGreaterOrEqual(dl, dr); + return opGreaterOrEqual(dl, dr, expr); } } } return new ArrayList(); } - private List opMemberOf(ExecutionContext context, List left, List right) throws FHIRException { + private List opMemberOf(ExecutionContext context, List left, List right, ExpressionNode expr) throws FHIRException { boolean ans = false; ValueSet vs = hostServices != null ? hostServices.resolveValueSet(context.appInfo, right.get(0).primitiveValue()) : worker.fetchResource(ValueSet.class, right.get(0).primitiveValue()); if (vs != null) { @@ -2338,7 +2344,7 @@ public class FHIRPathEngine { return makeBoolean(ans); } - private List opIn(List left, List right) throws FHIRException { + private List opIn(List left, List right, ExpressionNode expr) throws FHIRException { if (left.size() == 0) { return new ArrayList(); } @@ -2363,7 +2369,7 @@ public class FHIRPathEngine { return makeBoolean(ans); } - private List opContains(List left, List right) { + private List opContains(List left, List right, ExpressionNode expr) { if (left.size() == 0 || right.size() == 0) { return new ArrayList(); } @@ -2385,21 +2391,21 @@ public class FHIRPathEngine { return makeBoolean(ans); } - private List opPlus(List left, List right) throws PathEngineException { + private List opPlus(List left, List right, ExpressionNode expr) throws PathEngineException { if (left.size() == 0 || right.size() == 0) { return new ArrayList(); } if (left.size() > 1) { - throw makeException(I18nConstants.FHIRPATH_LEFT_VALUE_PLURAL, "+"); + throw makeException(expr, I18nConstants.FHIRPATH_LEFT_VALUE_PLURAL, "+"); } if (!left.get(0).isPrimitive()) { - throw makeException(I18nConstants.FHIRPATH_LEFT_VALUE_WRONG_TYPE, "+", left.get(0).fhirType()); + throw makeException(expr, I18nConstants.FHIRPATH_LEFT_VALUE_WRONG_TYPE, "+", left.get(0).fhirType()); } if (right.size() > 1) { - throw makeException(I18nConstants.FHIRPATH_RIGHT_VALUE_PLURAL, "+"); + throw makeException(expr, I18nConstants.FHIRPATH_RIGHT_VALUE_PLURAL, "+"); } if (!right.get(0).isPrimitive() && !((left.get(0).isDateTime() || "0".equals(left.get(0).primitiveValue()) || left.get(0).hasType("Quantity")) && right.get(0).hasType("Quantity"))) { - throw makeException(I18nConstants.FHIRPATH_RIGHT_VALUE_WRONG_TYPE, "+", right.get(0).fhirType()); + throw makeException(expr, I18nConstants.FHIRPATH_RIGHT_VALUE_WRONG_TYPE, "+", right.get(0).fhirType()); } List result = new ArrayList(); @@ -2412,14 +2418,14 @@ public class FHIRPathEngine { } else if (l.hasType("decimal", "integer") && r.hasType("decimal", "integer")) { result.add(new DecimalType(new BigDecimal(l.primitiveValue()).add(new BigDecimal(r.primitiveValue())))); } else if (l.isDateTime() && r.hasType("Quantity")) { - result.add(dateAdd((BaseDateTimeType) l, (Quantity) r, false)); + result.add(dateAdd((BaseDateTimeType) l, (Quantity) r, false, expr)); } else { - throw makeException(I18nConstants.FHIRPATH_OP_INCOMPATIBLE, "+", left.get(0).fhirType(), right.get(0).fhirType()); + throw makeException(expr, I18nConstants.FHIRPATH_OP_INCOMPATIBLE, "+", left.get(0).fhirType(), right.get(0).fhirType()); } return result; } - private BaseDateTimeType dateAdd(BaseDateTimeType d, Quantity q, boolean negate) { + private BaseDateTimeType dateAdd(BaseDateTimeType d, Quantity q, boolean negate, ExpressionNode holder) { BaseDateTimeType result = (BaseDateTimeType) d.copy(); int value = negate ? 0 - q.getValue().intValue() : q.getValue().intValue(); @@ -2435,7 +2441,7 @@ public class FHIRPathEngine { result.add(Calendar.MONTH, value); break; case "mo": - throw new PathEngineException(String.format("Error in date arithmetic: attempt to add a definite quantity duration time unit %s", q.getCode())); + throw new PathEngineException(String.format("Error in date arithmetic: attempt to add a definite quantity duration time unit %s", q.getCode()), holder.getOpStart(), holder.toString()); case "weeks": case "week": case "wk": @@ -2472,21 +2478,21 @@ public class FHIRPathEngine { return result; } - private List opTimes(List left, List right) throws PathEngineException { + private List opTimes(List left, List right, ExpressionNode expr) throws PathEngineException { if (left.size() == 0 || right.size() == 0) { return new ArrayList(); } if (left.size() > 1) { - throw makeException(I18nConstants.FHIRPATH_LEFT_VALUE_PLURAL, "*"); + throw makeException(expr, I18nConstants.FHIRPATH_LEFT_VALUE_PLURAL, "*"); } if (!left.get(0).isPrimitive() && !(left.get(0) instanceof Quantity)) { - throw makeException(I18nConstants.FHIRPATH_LEFT_VALUE_WRONG_TYPE, "*", left.get(0).fhirType()); + throw makeException(expr, I18nConstants.FHIRPATH_LEFT_VALUE_WRONG_TYPE, "*", left.get(0).fhirType()); } if (right.size() > 1) { - throw makeException(I18nConstants.FHIRPATH_RIGHT_VALUE_PLURAL, "*"); + throw makeException(expr, I18nConstants.FHIRPATH_RIGHT_VALUE_PLURAL, "*"); } if (!right.get(0).isPrimitive() && !(right.get(0) instanceof Quantity)) { - throw makeException(I18nConstants.FHIRPATH_RIGHT_VALUE_WRONG_TYPE, "*", right.get(0).fhirType()); + throw makeException(expr, I18nConstants.FHIRPATH_RIGHT_VALUE_WRONG_TYPE, "*", right.get(0).fhirType()); } List result = new ArrayList(); @@ -2505,27 +2511,27 @@ public class FHIRPathEngine { p = worker.getUcumService().multiply(pl, pr); result.add(pairToQty(p)); } catch (UcumException e) { - throw new PathEngineException(e.getMessage(), e); + throw new PathEngineException(e.getMessage(), expr.getOpStart(), expr.toString(), e); } } else { - throw makeException(I18nConstants.FHIRPATH_OP_INCOMPATIBLE, "*", left.get(0).fhirType(), right.get(0).fhirType()); + throw makeException(expr, I18nConstants.FHIRPATH_OP_INCOMPATIBLE, "*", left.get(0).fhirType(), right.get(0).fhirType()); } return result; } - private List opConcatenate(List left, List right) throws PathEngineException { + private List opConcatenate(List left, List right, ExpressionNode expr) throws PathEngineException { if (left.size() > 1) { - throw makeException(I18nConstants.FHIRPATH_LEFT_VALUE_PLURAL, "&"); + throw makeException(expr, I18nConstants.FHIRPATH_LEFT_VALUE_PLURAL, "&"); } if (left.size() > 0 && !left.get(0).hasType(FHIR_TYPES_STRING)) { - throw makeException(I18nConstants.FHIRPATH_LEFT_VALUE_WRONG_TYPE, "&", left.get(0).fhirType()); + throw makeException(expr, I18nConstants.FHIRPATH_LEFT_VALUE_WRONG_TYPE, "&", left.get(0).fhirType()); } if (right.size() > 1) { - throw makeException(I18nConstants.FHIRPATH_RIGHT_VALUE_PLURAL, "&"); + throw makeException(expr, I18nConstants.FHIRPATH_RIGHT_VALUE_PLURAL, "&"); } if (right.size() > 0 && !right.get(0).hasType(FHIR_TYPES_STRING)) { - throw makeException(I18nConstants.FHIRPATH_RIGHT_VALUE_WRONG_TYPE, "&", right.get(0).fhirType()); + throw makeException(expr, I18nConstants.FHIRPATH_RIGHT_VALUE_WRONG_TYPE, "&", right.get(0).fhirType()); } List result = new ArrayList(); @@ -2535,7 +2541,7 @@ public class FHIRPathEngine { return result; } - private List opUnion(List left, List right) { + private List opUnion(List left, List right, ExpressionNode expr) { List result = new ArrayList(); for (Base item : left) { if (!doContains(result, item)) { @@ -2561,9 +2567,9 @@ public class FHIRPathEngine { } - private List opAnd(List left, List right) throws PathEngineException { - Equality l = asBool(left); - Equality r = asBool(right); + private List opAnd(List left, List right, ExpressionNode expr) throws PathEngineException { + Equality l = asBool(left, expr); + Equality r = asBool(right, expr); switch (l) { case False: return makeBoolean(false); case Null: @@ -2586,9 +2592,9 @@ public class FHIRPathEngine { return list.size() == 1 && list.get(0) instanceof BooleanType && ((BooleanType) list.get(0)).booleanValue() == b; } - private List opOr(List left, List right) throws PathEngineException { - Equality l = asBool(left); - Equality r = asBool(right); + private List opOr(List left, List right, ExpressionNode expr) throws PathEngineException { + Equality l = asBool(left, expr); + Equality r = asBool(right, expr); switch (l) { case True: return makeBoolean(true); case Null: @@ -2607,9 +2613,9 @@ public class FHIRPathEngine { return makeNull(); } - private List opXor(List left, List right) throws PathEngineException { - Equality l = asBool(left); - Equality r = asBool(right); + private List opXor(List left, List right, ExpressionNode expr) throws PathEngineException { + Equality l = asBool(left, expr); + Equality r = asBool(right, expr); switch (l) { case True: switch (r) { @@ -2629,13 +2635,13 @@ public class FHIRPathEngine { return makeNull(); } - private List opImplies(List left, List right) throws PathEngineException { - Equality eq = asBool(left); + private List opImplies(List left, List right, ExpressionNode expr) throws PathEngineException { + Equality eq = asBool(left, expr); if (eq == Equality.False) { return makeBoolean(true); } else if (right.size() == 0) { return makeNull(); - } else switch (asBool(right)) { + } else switch (asBool(right, expr)) { case False: return eq == Equality.Null ? makeNull() : makeBoolean(false); case Null: return makeNull(); case True: return makeBoolean(true); @@ -2644,21 +2650,21 @@ public class FHIRPathEngine { } - private List opMinus(List left, List right) throws PathEngineException { + private List opMinus(List left, List right, ExpressionNode expr) throws PathEngineException { if (left.size() == 0 || right.size() == 0) { return new ArrayList(); } if (left.size() > 1) { - throw makeException(I18nConstants.FHIRPATH_LEFT_VALUE_PLURAL, "-"); + throw makeException(expr, I18nConstants.FHIRPATH_LEFT_VALUE_PLURAL, "-"); } if (!left.get(0).isPrimitive() && !left.get(0).hasType("Quantity")) { - throw makeException(I18nConstants.FHIRPATH_LEFT_VALUE_WRONG_TYPE, "-", left.get(0).fhirType()); + throw makeException(expr, I18nConstants.FHIRPATH_LEFT_VALUE_WRONG_TYPE, "-", left.get(0).fhirType()); } if (right.size() > 1) { - throw makeException(I18nConstants.FHIRPATH_RIGHT_VALUE_PLURAL, "-"); + throw makeException(expr, I18nConstants.FHIRPATH_RIGHT_VALUE_PLURAL, "-"); } if (!right.get(0).isPrimitive() && !((left.get(0).isDateTime() || "0".equals(left.get(0).primitiveValue()) || left.get(0).hasType("Quantity")) && right.get(0).hasType("Quantity"))) { - throw makeException(I18nConstants.FHIRPATH_RIGHT_VALUE_WRONG_TYPE, "-", right.get(0).fhirType()); + throw makeException(expr, I18nConstants.FHIRPATH_RIGHT_VALUE_WRONG_TYPE, "-", right.get(0).fhirType()); } List result = new ArrayList(); @@ -2676,28 +2682,28 @@ public class FHIRPathEngine { result.add(qty.copy().setValue(qty.getValue().abs())); } } else if (l.isDateTime() && r.hasType("Quantity")) { - result.add(dateAdd((BaseDateTimeType) l, (Quantity) r, true)); + result.add(dateAdd((BaseDateTimeType) l, (Quantity) r, true, expr)); } else { - throw makeException(I18nConstants.FHIRPATH_OP_INCOMPATIBLE, "-", left.get(0).fhirType(), right.get(0).fhirType()); + throw makeException(expr, I18nConstants.FHIRPATH_OP_INCOMPATIBLE, "-", left.get(0).fhirType(), right.get(0).fhirType()); } return result; } - private List opDivideBy(List left, List right) throws PathEngineException { + private List opDivideBy(List left, List right, ExpressionNode expr) throws PathEngineException { if (left.size() == 0 || right.size() == 0) { return new ArrayList(); } if (left.size() > 1) { - throw makeException(I18nConstants.FHIRPATH_LEFT_VALUE_PLURAL, "/"); + throw makeException(expr, I18nConstants.FHIRPATH_LEFT_VALUE_PLURAL, "/"); } if (!left.get(0).isPrimitive() && !(left.get(0) instanceof Quantity)) { - throw makeException(I18nConstants.FHIRPATH_LEFT_VALUE_WRONG_TYPE, "/", left.get(0).fhirType()); + throw makeException(expr, I18nConstants.FHIRPATH_LEFT_VALUE_WRONG_TYPE, "/", left.get(0).fhirType()); } if (right.size() > 1) { - throw makeException(I18nConstants.FHIRPATH_RIGHT_VALUE_PLURAL, "/"); + throw makeException(expr, I18nConstants.FHIRPATH_RIGHT_VALUE_PLURAL, "/"); } if (!right.get(0).isPrimitive() && !(right.get(0) instanceof Quantity)) { - throw makeException(I18nConstants.FHIRPATH_RIGHT_VALUE_WRONG_TYPE, "/", right.get(0).fhirType()); + throw makeException(expr, I18nConstants.FHIRPATH_RIGHT_VALUE_WRONG_TYPE, "/", right.get(0).fhirType()); } List result = new ArrayList(); @@ -2724,26 +2730,26 @@ public class FHIRPathEngine { // just return nothing } } else { - throw makeException(I18nConstants.FHIRPATH_OP_INCOMPATIBLE, "/", left.get(0).fhirType(), right.get(0).fhirType()); + throw makeException(expr, I18nConstants.FHIRPATH_OP_INCOMPATIBLE, "/", left.get(0).fhirType(), right.get(0).fhirType()); } return result; } - private List opDiv(List left, List right) throws PathEngineException { + private List opDiv(List left, List right, ExpressionNode expr) throws PathEngineException { if (left.size() == 0 || right.size() == 0) { return new ArrayList(); } if (left.size() > 1) { - throw makeException(I18nConstants.FHIRPATH_LEFT_VALUE_PLURAL, "div"); + throw makeException(expr, I18nConstants.FHIRPATH_LEFT_VALUE_PLURAL, "div"); } if (!left.get(0).isPrimitive() && !(left.get(0) instanceof Quantity)) { - throw makeException(I18nConstants.FHIRPATH_LEFT_VALUE_WRONG_TYPE, "div", left.get(0).fhirType()); + throw makeException(expr, I18nConstants.FHIRPATH_LEFT_VALUE_WRONG_TYPE, "div", left.get(0).fhirType()); } if (right.size() > 1) { - throw makeException(I18nConstants.FHIRPATH_RIGHT_VALUE_PLURAL, "div"); + throw makeException(expr, I18nConstants.FHIRPATH_RIGHT_VALUE_PLURAL, "div"); } if (!right.get(0).isPrimitive() && !(right.get(0) instanceof Quantity)) { - throw makeException(I18nConstants.FHIRPATH_RIGHT_VALUE_WRONG_TYPE, "div", right.get(0).fhirType()); + throw makeException(expr, I18nConstants.FHIRPATH_RIGHT_VALUE_WRONG_TYPE, "div", right.get(0).fhirType()); } List result = new ArrayList(); @@ -2765,25 +2771,25 @@ public class FHIRPathEngine { // just return nothing } } else { - throw makeException(I18nConstants.FHIRPATH_OP_INCOMPATIBLE, "div", left.get(0).fhirType(), right.get(0).fhirType()); + throw makeException(expr, I18nConstants.FHIRPATH_OP_INCOMPATIBLE, "div", left.get(0).fhirType(), right.get(0).fhirType()); } return result; } - private List opMod(List left, List right) throws PathEngineException { + private List opMod(List left, List right, ExpressionNode expr) throws PathEngineException { if (left.size() == 0 || right.size() == 0) { return new ArrayList(); } if (left.size() > 1) { - throw makeException(I18nConstants.FHIRPATH_LEFT_VALUE_PLURAL, "mod"); + throw makeException(expr, I18nConstants.FHIRPATH_LEFT_VALUE_PLURAL, "mod"); } if (!left.get(0).isPrimitive()) { - throw makeException(I18nConstants.FHIRPATH_LEFT_VALUE_WRONG_TYPE, "mod", left.get(0).fhirType()); + throw makeException(expr, I18nConstants.FHIRPATH_LEFT_VALUE_WRONG_TYPE, "mod", left.get(0).fhirType()); } if (right.size() > 1) { - throw makeException(I18nConstants.FHIRPATH_RIGHT_VALUE_PLURAL, "mod"); + throw makeException(expr, I18nConstants.FHIRPATH_RIGHT_VALUE_PLURAL, "mod"); } if (!right.get(0).isPrimitive()) { - throw makeException(I18nConstants.FHIRPATH_RIGHT_VALUE_WRONG_TYPE, "mod", right.get(0).fhirType()); + throw makeException(expr, I18nConstants.FHIRPATH_RIGHT_VALUE_WRONG_TYPE, "mod", right.get(0).fhirType()); } List result = new ArrayList(); @@ -2805,13 +2811,13 @@ public class FHIRPathEngine { throw new PathEngineException(e); } } else { - throw makeException(I18nConstants.FHIRPATH_OP_INCOMPATIBLE, "mod", left.get(0).fhirType(), right.get(0).fhirType()); + throw makeException(expr, I18nConstants.FHIRPATH_OP_INCOMPATIBLE, "mod", left.get(0).fhirType(), right.get(0).fhirType()); } return result; } - private TypeDetails resolveConstantType(ExecutionTypeContext context, Base constant) throws PathEngineException { + private TypeDetails resolveConstantType(ExecutionTypeContext context, Base constant, ExpressionNode expr) throws PathEngineException { if (constant instanceof BooleanType) { return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } else if (constant instanceof IntegerType) { @@ -2821,13 +2827,13 @@ public class FHIRPathEngine { } else if (constant instanceof Quantity) { return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Quantity); } else if (constant instanceof FHIRConstant) { - return resolveConstantType(context, ((FHIRConstant) constant).getValue()); + return resolveConstantType(context, ((FHIRConstant) constant).getValue(), expr); } else { return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); } } - private TypeDetails resolveConstantType(ExecutionTypeContext context, String s) throws PathEngineException { + private TypeDetails resolveConstantType(ExecutionTypeContext context, String s, ExpressionNode expr) throws PathEngineException { if (s.startsWith("@")) { if (s.startsWith("@T")) { return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Time); @@ -2842,12 +2848,12 @@ public class FHIRPathEngine { return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); } else if (s.equals("%resource")) { if (context.resource == null) { - throw makeException(I18nConstants.FHIRPATH_CANNOT_USE, "%resource", "no focus resource"); + throw makeException(expr, I18nConstants.FHIRPATH_CANNOT_USE, "%resource", "no focus resource"); } return new TypeDetails(CollectionStatus.SINGLETON, context.resource); } else if (s.equals("%rootResource")) { if (context.resource == null) { - throw makeException(I18nConstants.FHIRPATH_CANNOT_USE, "%rootResource", "no focus resource"); + throw makeException(expr, I18nConstants.FHIRPATH_CANNOT_USE, "%rootResource", "no focus resource"); } return new TypeDetails(CollectionStatus.SINGLETON, context.resource); } else if (s.equals("%context")) { @@ -2863,7 +2869,7 @@ public class FHIRPathEngine { } else if (s.startsWith("%`ext-")) { return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); } else if (hostServices == null) { - throw makeException(I18nConstants.FHIRPATH_UNKNOWN_CONSTANT, s); + throw makeException(expr, I18nConstants.FHIRPATH_UNKNOWN_CONSTANT, s); } else { return hostServices.resolveConstantType(context.appInfo, s); } @@ -2914,9 +2920,9 @@ public class FHIRPathEngine { } - private TypeDetails executeContextType(ExecutionTypeContext context, String name) throws PathEngineException, DefinitionException { + private TypeDetails executeContextType(ExecutionTypeContext context, String name, ExpressionNode expr) throws PathEngineException, DefinitionException { if (hostServices == null) { - throw makeException(I18nConstants.FHIRPATH_HO_HOST_SERVICES, "Context Reference"); + throw makeException(expr, I18nConstants.FHIRPATH_HO_HOST_SERVICES, "Context Reference"); } return hostServices.resolveConstantType(context.appInfo, name); } @@ -2926,7 +2932,7 @@ public class FHIRPathEngine { return new TypeDetails(CollectionStatus.SINGLETON, type); } TypeDetails result = new TypeDetails(null); - getChildTypesByName(type, exp.getName(), result); + getChildTypesByName(type, exp.getName(), result, exp); return result; } @@ -2956,15 +2962,15 @@ public class FHIRPathEngine { case Not : return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); case Exists : { - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case SubsetOf : { - checkParamTypes(exp.getFunction().toCode(), paramTypes, focus); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, focus); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case SupersetOf : { - checkParamTypes(exp.getFunction().toCode(), paramTypes, focus); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, focus); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case IsDistinct : @@ -2984,16 +2990,16 @@ public class FHIRPathEngine { case Aggregate : return anything(focus.getCollectionStatus()); case Item : { - checkOrdered(focus, "item"); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer)); + checkOrdered(focus, "item", exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer)); return focus; } case As : { - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, exp.getParameters().get(0).getName()); } case OfType : { - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, exp.getParameters().get(0).getName()); } case Type : { @@ -3012,31 +3018,31 @@ public class FHIRPathEngine { } } case Is : { - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case Single : return focus.toSingleton(); case First : { - checkOrdered(focus, "first"); + checkOrdered(focus, "first", exp); return focus.toSingleton(); } case Last : { - checkOrdered(focus, "last"); + checkOrdered(focus, "last", exp); return focus.toSingleton(); } case Tail : { - checkOrdered(focus, "tail"); + checkOrdered(focus, "tail", exp); return focus; } case Skip : { - checkOrdered(focus, "skip"); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer)); + checkOrdered(focus, "skip", exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer)); return focus; } case Take : { - checkOrdered(focus, "take"); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer)); + checkOrdered(focus, "take", exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer)); return focus; } case Union : { @@ -3060,76 +3066,76 @@ public class FHIRPathEngine { return types; } case Lower : { - checkContextString(focus, "lower"); + checkContextString(focus, "lower", exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); } case Upper : { - checkContextString(focus, "upper"); + checkContextString(focus, "upper", exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); } case ToChars : { - checkContextString(focus, "toChars"); + checkContextString(focus, "toChars", exp); return new TypeDetails(CollectionStatus.ORDERED, TypeDetails.FP_String); } case IndexOf : { - checkContextString(focus, "indexOf"); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkContextString(focus, "indexOf", exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer); } case Substring : { - checkContextString(focus, "subString"); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer), new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer)); + checkContextString(focus, "subString", exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer), new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); } case StartsWith : { - checkContextString(focus, "startsWith"); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkContextString(focus, "startsWith", exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case EndsWith : { - checkContextString(focus, "endsWith"); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkContextString(focus, "endsWith", exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case Matches : { - checkContextString(focus, "matches"); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkContextString(focus, "matches", exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case ReplaceMatches : { - checkContextString(focus, "replaceMatches"); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String), new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkContextString(focus, "replaceMatches", exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String), new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); } case Contains : { - checkContextString(focus, "contains"); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkContextString(focus, "contains", exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case Replace : { - checkContextString(focus, "replace"); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, "string"), new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkContextString(focus, "replace", exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, "string"), new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); } case Length : { - checkContextPrimitive(focus, "length", false); + checkContextPrimitive(focus, "length", false, exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer); } case Children : - return childTypes(focus, "*"); + return childTypes(focus, "*", exp); case Descendants : - return childTypes(focus, "**"); + return childTypes(focus, "**", exp); case MemberOf : { - checkContextCoded(focus, "memberOf"); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkContextCoded(focus, "memberOf", exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case Trace : { - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return focus; } case Check : { - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return focus; } case Today : @@ -3137,11 +3143,11 @@ public class FHIRPathEngine { case Now : return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_DateTime); case Resolve : { - checkContextReference(focus, "resolve"); + checkContextReference(focus, "resolve", exp); return new TypeDetails(CollectionStatus.SINGLETON, "DomainResource"); } case Extension : { - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, "Extension"); } case AnyTrue: @@ -3159,62 +3165,62 @@ public class FHIRPathEngine { case HtmlChecks2 : return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); case Alias : - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return anything(CollectionStatus.SINGLETON); case AliasAs : - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return focus; case Encode: - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); case Decode: - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); case Escape: - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); case Unescape: - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); case Trim: return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); case Split: - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); case Join: - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); case ToInteger : { - checkContextPrimitive(focus, "toInteger", true); + checkContextPrimitive(focus, "toInteger", true, exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer); } case ToDecimal : { - checkContextPrimitive(focus, "toDecimal", true); + checkContextPrimitive(focus, "toDecimal", true, exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Decimal); } case ToString : { - checkContextPrimitive(focus, "toString", true); + checkContextPrimitive(focus, "toString", true, exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); } case ToQuantity : { - checkContextPrimitive(focus, "toQuantity", true); + checkContextPrimitive(focus, "toQuantity", true, exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Quantity); } case ToBoolean : { - checkContextPrimitive(focus, "toBoolean", false); + checkContextPrimitive(focus, "toBoolean", false, exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case ToDateTime : { - checkContextPrimitive(focus, "ToDateTime", false); + checkContextPrimitive(focus, "ToDateTime", false, exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_DateTime); } case ToTime : { - checkContextPrimitive(focus, "ToTime", false); + checkContextPrimitive(focus, "ToTime", false, exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Time); } case ConvertsToString : case ConvertsToQuantity :{ - checkContextPrimitive(focus, exp.getFunction().toCode(), true); + checkContextPrimitive(focus, exp.getFunction().toCode(), true, exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case ConvertsToInteger : @@ -3223,28 +3229,28 @@ public class FHIRPathEngine { case ConvertsToDate : case ConvertsToTime : case ConvertsToBoolean : { - checkContextPrimitive(focus, exp.getFunction().toCode(), false); + checkContextPrimitive(focus, exp.getFunction().toCode(), false, exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case ConformsTo: { - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case Abs : { - checkContextNumerical(focus, "abs"); + checkContextNumerical(focus, "abs", exp); return new TypeDetails(CollectionStatus.SINGLETON, focus.getTypes()); } case Truncate : case Floor : case Ceiling : { - checkContextDecimal(focus, exp.getFunction().toCode()); + checkContextDecimal(focus, exp.getFunction().toCode(), exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer); } case Round :{ - checkContextDecimal(focus, "round"); + checkContextDecimal(focus, "round", exp); if (paramTypes.size() > 0) { - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer)); } return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Decimal); } @@ -3252,17 +3258,17 @@ public class FHIRPathEngine { case Exp : case Ln : case Sqrt : { - checkContextNumerical(focus, exp.getFunction().toCode()); + checkContextNumerical(focus, exp.getFunction().toCode(), exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Decimal); } case Log : { - checkContextNumerical(focus, exp.getFunction().toCode()); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_NUMBERS)); + checkContextNumerical(focus, exp.getFunction().toCode(), exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_NUMBERS)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Decimal); } case Power : { - checkContextNumerical(focus, exp.getFunction().toCode()); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_NUMBERS)); + checkContextNumerical(focus, exp.getFunction().toCode(), exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_NUMBERS)); return new TypeDetails(CollectionStatus.SINGLETON, focus.getTypes()); } @@ -3276,7 +3282,7 @@ public class FHIRPathEngine { } - private void checkParamTypes(String funcName, List paramTypes, TypeDetails... typeSet) throws PathEngineException { + private void checkParamTypes(ExpressionNode expr, String funcName, List paramTypes, TypeDetails... typeSet) throws PathEngineException { int i = 0; for (TypeDetails pt : typeSet) { if (i == paramTypes.size()) { @@ -3286,65 +3292,65 @@ public class FHIRPathEngine { i++; for (String a : actual.getTypes()) { if (!pt.hasType(worker, a)) { - throw makeException(I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, funcName, i, a, pt.toString()); + throw makeException(expr, I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, funcName, i, a, pt.toString()); } } } } - private void checkOrdered(TypeDetails focus, String name) throws PathEngineException { + private void checkOrdered(TypeDetails focus, String name, ExpressionNode expr) throws PathEngineException { if (focus.getCollectionStatus() == CollectionStatus.UNORDERED) { - throw makeException(I18nConstants.FHIRPATH_ORDERED_ONLY, name); + throw makeException(expr, I18nConstants.FHIRPATH_ORDERED_ONLY, name); } } - private void checkContextReference(TypeDetails focus, String name) throws PathEngineException { + private void checkContextReference(TypeDetails focus, String name, ExpressionNode expr) throws PathEngineException { if (!focus.hasType(worker, "string") && !focus.hasType(worker, "uri") && !focus.hasType(worker, "Reference") && !focus.hasType(worker, "canonical")) { - throw makeException(I18nConstants.FHIRPATH_REFERENCE_ONLY, name, focus.describe()); + throw makeException(expr, I18nConstants.FHIRPATH_REFERENCE_ONLY, name, focus.describe()); } } - private void checkContextCoded(TypeDetails focus, String name) throws PathEngineException { + private void checkContextCoded(TypeDetails focus, String name, ExpressionNode expr) throws PathEngineException { if (!focus.hasType(worker, "string") && !focus.hasType(worker, "code") && !focus.hasType(worker, "uri") && !focus.hasType(worker, "Coding") && !focus.hasType(worker, "CodeableConcept")) { - throw makeException(I18nConstants.FHIRPATH_CODED_ONLY, name, focus.describe()); + throw makeException(expr, I18nConstants.FHIRPATH_CODED_ONLY, name, focus.describe()); } } - private void checkContextString(TypeDetails focus, String name) throws PathEngineException { + private void checkContextString(TypeDetails focus, String name, ExpressionNode expr) throws PathEngineException { if (!focus.hasType(worker, "string") && !focus.hasType(worker, "code") && !focus.hasType(worker, "uri") && !focus.hasType(worker, "canonical") && !focus.hasType(worker, "id")) { - throw makeException(I18nConstants.FHIRPATH_STRING_ONLY, name, focus.describe()); + throw makeException(expr, I18nConstants.FHIRPATH_STRING_ONLY, name, focus.describe()); } } - private void checkContextPrimitive(TypeDetails focus, String name, boolean canQty) throws PathEngineException { + private void checkContextPrimitive(TypeDetails focus, String name, boolean canQty, ExpressionNode expr) throws PathEngineException { if (canQty) { if (!focus.hasType(primitiveTypes) && !focus.hasType("Quantity")) { - throw makeException(I18nConstants.FHIRPATH_PRIMITIVE_ONLY, name, focus.describe(), "Quantity, "+primitiveTypes.toString()); + throw makeException(expr, I18nConstants.FHIRPATH_PRIMITIVE_ONLY, name, focus.describe(), "Quantity, "+primitiveTypes.toString()); } } else if (!focus.hasType(primitiveTypes)) { - throw makeException(I18nConstants.FHIRPATH_PRIMITIVE_ONLY, name, focus.describe(), primitiveTypes.toString()); + throw makeException(expr, I18nConstants.FHIRPATH_PRIMITIVE_ONLY, name, focus.describe(), primitiveTypes.toString()); } } - private void checkContextNumerical(TypeDetails focus, String name) throws PathEngineException { + private void checkContextNumerical(TypeDetails focus, String name, ExpressionNode expr) throws PathEngineException { if (!focus.hasType("integer") && !focus.hasType("decimal") && !focus.hasType("Quantity")) { - throw makeException(I18nConstants.FHIRPATH_NUMERICAL_ONLY, name, focus.describe()); + throw makeException(expr, I18nConstants.FHIRPATH_NUMERICAL_ONLY, name, focus.describe()); } } - private void checkContextDecimal(TypeDetails focus, String name) throws PathEngineException { + private void checkContextDecimal(TypeDetails focus, String name, ExpressionNode expr) throws PathEngineException { if (!focus.hasType("decimal") && !focus.hasType("integer")) { - throw makeException(I18nConstants.FHIRPATH_DECIMAL_ONLY, name, focus.describe()); + throw makeException(expr, I18nConstants.FHIRPATH_DECIMAL_ONLY, name, focus.describe()); } } - private TypeDetails childTypes(TypeDetails focus, String mask) throws PathEngineException, DefinitionException { + private TypeDetails childTypes(TypeDetails focus, String mask, ExpressionNode expr) throws PathEngineException, DefinitionException { TypeDetails result = new TypeDetails(CollectionStatus.UNORDERED); for (String f : focus.getTypes()) { - getChildTypesByName(f, mask, result); + getChildTypesByName(f, mask, result, expr); } return result; } @@ -3464,9 +3470,9 @@ public class FHIRPathEngine { } } - private List funcSqrt(ExecutionContext context, List focus, ExpressionNode exp) { + private List funcSqrt(ExecutionContext context, List focus, ExpressionNode expr) { if (focus.size() != 1) { - throw makeException(I18nConstants.FHIRPATH_FOCUS_PLURAL, "sqrt", focus.size()); + throw makeException(expr, I18nConstants.FHIRPATH_FOCUS_PLURAL, "sqrt", focus.size()); } Base base = focus.get(0); List result = new ArrayList(); @@ -3478,15 +3484,15 @@ public class FHIRPathEngine { // just return nothing } } else { - makeException(I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "sqrt", "(focus)", base.fhirType(), "integer or decimal"); + makeException(expr, I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "sqrt", "(focus)", base.fhirType(), "integer or decimal"); } return result; } - private List funcAbs(ExecutionContext context, List focus, ExpressionNode exp) { + private List funcAbs(ExecutionContext context, List focus, ExpressionNode expr) { if (focus.size() != 1) { - throw makeException(I18nConstants.FHIRPATH_FOCUS_PLURAL, "abs", focus.size()); + throw makeException(expr, I18nConstants.FHIRPATH_FOCUS_PLURAL, "abs", focus.size()); } Base base = focus.get(0); List result = new ArrayList(); @@ -3501,15 +3507,15 @@ public class FHIRPathEngine { Quantity qty = (Quantity) base; result.add(qty.copy().setValue(qty.getValue().abs())); } else { - makeException(I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "abs", "(focus)", base.fhirType(), "integer or decimal"); + makeException(expr, I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "abs", "(focus)", base.fhirType(), "integer or decimal"); } return result; } - private List funcCeiling(ExecutionContext context, List focus, ExpressionNode exp) { + private List funcCeiling(ExecutionContext context, List focus, ExpressionNode expr) { if (focus.size() != 1) { - throw makeException(I18nConstants.FHIRPATH_FOCUS_PLURAL, "ceiling", focus.size()); + throw makeException(expr, I18nConstants.FHIRPATH_FOCUS_PLURAL, "ceiling", focus.size()); } Base base = focus.get(0); List result = new ArrayList(); @@ -3520,14 +3526,14 @@ public class FHIRPathEngine { // just return nothing } } else { - makeException(I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "ceiling", "(focus)", base.fhirType(), "integer or decimal"); + makeException(expr, I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "ceiling", "(focus)", base.fhirType(), "integer or decimal"); } return result; } - private List funcFloor(ExecutionContext context, List focus, ExpressionNode exp) { + private List funcFloor(ExecutionContext context, List focus, ExpressionNode expr) { if (focus.size() != 1) { - throw makeException(I18nConstants.FHIRPATH_FOCUS_PLURAL, "floor", focus.size()); + throw makeException(expr, I18nConstants.FHIRPATH_FOCUS_PLURAL, "floor", focus.size()); } Base base = focus.get(0); List result = new ArrayList(); @@ -3539,15 +3545,15 @@ public class FHIRPathEngine { // just return nothing } } else { - makeException(I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "floor", "(focus)", base.fhirType(), "integer or decimal"); + makeException(expr, I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "floor", "(focus)", base.fhirType(), "integer or decimal"); } return result; } - private List funcExp(ExecutionContext context, List focus, ExpressionNode exp) { + private List funcExp(ExecutionContext context, List focus, ExpressionNode expr) { if (focus.size() != 1) { - throw makeException(I18nConstants.FHIRPATH_FOCUS_PLURAL, "exp", focus.size()); + throw makeException(expr, I18nConstants.FHIRPATH_FOCUS_PLURAL, "exp", focus.size()); } Base base = focus.get(0); List result = new ArrayList(); @@ -3560,15 +3566,15 @@ public class FHIRPathEngine { } } else { - makeException(I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "exp", "(focus)", base.fhirType(), "integer or decimal"); + makeException(expr, I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "exp", "(focus)", base.fhirType(), "integer or decimal"); } return result; } - private List funcLn(ExecutionContext context, List focus, ExpressionNode exp) { + private List funcLn(ExecutionContext context, List focus, ExpressionNode expr) { if (focus.size() != 1) { - throw makeException(I18nConstants.FHIRPATH_FOCUS_PLURAL, "ln", focus.size()); + throw makeException(expr, I18nConstants.FHIRPATH_FOCUS_PLURAL, "ln", focus.size()); } Base base = focus.get(0); List result = new ArrayList(); @@ -3580,22 +3586,22 @@ public class FHIRPathEngine { // just return nothing } } else { - makeException(I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "ln", "(focus)", base.fhirType(), "integer or decimal"); + makeException(expr, I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "ln", "(focus)", base.fhirType(), "integer or decimal"); } return result; } - private List funcLog(ExecutionContext context, List focus, ExpressionNode exp) { + private List funcLog(ExecutionContext context, List focus, ExpressionNode expr) { if (focus.size() != 1) { - throw makeException(I18nConstants.FHIRPATH_FOCUS_PLURAL, "log", focus.size()); + throw makeException(expr, I18nConstants.FHIRPATH_FOCUS_PLURAL, "log", focus.size()); } Base base = focus.get(0); List result = new ArrayList(); if (base.hasType("integer", "decimal", "unsignedInt", "positiveInt")) { - List n1 = execute(context, focus, exp.getParameters().get(0), true); + List n1 = execute(context, focus, expr.getParameters().get(0), true); if (n1.size() != 1) { - throw makeException(I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "log", "0", "Multiple Values", "integer or decimal"); + throw makeException(expr, I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "log", "0", "Multiple Values", "integer or decimal"); } Double e = Double.parseDouble(n1.get(0).primitiveValue()); Double d = Double.parseDouble(base.primitiveValue()); @@ -3605,7 +3611,7 @@ public class FHIRPathEngine { // just return nothing } } else { - makeException(I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "log", "(focus)", base.fhirType(), "integer or decimal"); + makeException(expr, I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "log", "(focus)", base.fhirType(), "integer or decimal"); } return result; } @@ -3614,16 +3620,16 @@ public class FHIRPathEngine { return Math.log(logNumber) / Math.log(base); } - private List funcPower(ExecutionContext context, List focus, ExpressionNode exp) { + private List funcPower(ExecutionContext context, List focus, ExpressionNode expr) { if (focus.size() != 1) { - throw makeException(I18nConstants.FHIRPATH_FOCUS_PLURAL, "power", focus.size()); + throw makeException(expr, I18nConstants.FHIRPATH_FOCUS_PLURAL, "power", focus.size()); } Base base = focus.get(0); List result = new ArrayList(); if (base.hasType("integer", "decimal", "unsignedInt", "positiveInt")) { - List n1 = execute(context, focus, exp.getParameters().get(0), true); + List n1 = execute(context, focus, expr.getParameters().get(0), true); if (n1.size() != 1) { - throw makeException(I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "power", "0", "Multiple Values", "integer or decimal"); + throw makeException(expr, I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "power", "0", "Multiple Values", "integer or decimal"); } Double e = Double.parseDouble(n1.get(0).primitiveValue()); Double d = Double.parseDouble(base.primitiveValue()); @@ -3633,14 +3639,14 @@ public class FHIRPathEngine { // just return nothing } } else { - makeException(I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "power", "(focus)", base.fhirType(), "integer or decimal"); + makeException(expr, I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "power", "(focus)", base.fhirType(), "integer or decimal"); } return result; } - private List funcTruncate(ExecutionContext context, List focus, ExpressionNode exp) { + private List funcTruncate(ExecutionContext context, List focus, ExpressionNode expr) { if (focus.size() != 1) { - throw makeException(I18nConstants.FHIRPATH_FOCUS_PLURAL, "truncate", focus.size()); + throw makeException(expr, I18nConstants.FHIRPATH_FOCUS_PLURAL, "truncate", focus.size()); } Base base = focus.get(0); List result = new ArrayList(); @@ -3651,30 +3657,30 @@ public class FHIRPathEngine { } result.add(new IntegerType(s)); } else { - makeException(I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "sqrt", "(focus)", base.fhirType(), "integer or decimal"); + makeException(expr, I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "sqrt", "(focus)", base.fhirType(), "integer or decimal"); } return result; } - private List funcRound(ExecutionContext context, List focus, ExpressionNode exp) { + private List funcRound(ExecutionContext context, List focus, ExpressionNode expr) { if (focus.size() != 1) { - throw makeException(I18nConstants.FHIRPATH_FOCUS_PLURAL, "round", focus.size()); + throw makeException(expr, I18nConstants.FHIRPATH_FOCUS_PLURAL, "round", focus.size()); } Base base = focus.get(0); List result = new ArrayList(); if (base.hasType("integer", "decimal", "unsignedInt", "positiveInt")) { int i = 0; - if (exp.getParameters().size() == 1) { - List n1 = execute(context, focus, exp.getParameters().get(0), true); + if (expr.getParameters().size() == 1) { + List n1 = execute(context, focus, expr.getParameters().get(0), true); if (n1.size() != 1) { - throw makeException(I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "power", "0", "Multiple Values", "integer"); + throw makeException(expr, I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "power", "0", "Multiple Values", "integer"); } i = Integer.parseInt(n1.get(0).primitiveValue()); } BigDecimal d = new BigDecimal (base.primitiveValue()); result.add(new DecimalType(d.setScale(i, RoundingMode.HALF_UP))); } else { - makeException(I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "round", "(focus)", base.fhirType(), "integer or decimal"); + makeException(expr, I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "round", "(focus)", base.fhirType(), "integer or decimal"); } return result; } @@ -3913,7 +3919,7 @@ public class FHIRPathEngine { for (Base item : focus) { pc.clear(); pc.add(item); - Equality eq = asBool(execute(changeThis(context, item), pc, exp.getParameters().get(0), true)); + Equality eq = asBool(execute(changeThis(context, item), pc, exp.getParameters().get(0), true), exp); if (eq != Equality.True) { all = false; break; @@ -4012,7 +4018,7 @@ public class FHIRPathEngine { } - private List funcReplace(ExecutionContext context, List focus, ExpressionNode exp) throws FHIRException, PathEngineException { + private List funcReplace(ExecutionContext context, List focus, ExpressionNode expr) throws FHIRException, PathEngineException { List result = new ArrayList(); if (focus.size() == 1) { @@ -4020,13 +4026,13 @@ public class FHIRPathEngine { if (Utilities.noString(f)) { result.add(new StringType("")); } else { - String t = convertToString(execute(context, focus, exp.getParameters().get(0), true)); - String r = convertToString(execute(context, focus, exp.getParameters().get(1), true)); + String t = convertToString(execute(context, focus, expr.getParameters().get(0), true)); + String r = convertToString(execute(context, focus, expr.getParameters().get(1), true)); String n = f.replace(t, r); result.add(new StringType(n)); } } else { - throw makeException(I18nConstants.FHIRPATH_NO_COLLECTION, "replace", focus.size()); + throw makeException(expr, I18nConstants.FHIRPATH_NO_COLLECTION, "replace", focus.size()); } return result; } @@ -4119,22 +4125,22 @@ public class FHIRPathEngine { return result; } - private List funcToDateTime(ExecutionContext context, List focus, ExpressionNode exp) { + private List funcToDateTime(ExecutionContext context, List focus, ExpressionNode expr) { // List result = new ArrayList(); // result.add(new BooleanType(convertToBoolean(focus))); // return result; - throw makeException(I18nConstants.FHIRPATH_NOT_IMPLEMENTED, "toDateTime"); + throw makeException(expr, I18nConstants.FHIRPATH_NOT_IMPLEMENTED, "toDateTime"); } - private List funcToTime(ExecutionContext context, List focus, ExpressionNode exp) { + private List funcToTime(ExecutionContext context, List focus, ExpressionNode expr) { // List result = new ArrayList(); // result.add(new BooleanType(convertToBoolean(focus))); // return result; - throw makeException(I18nConstants.FHIRPATH_NOT_IMPLEMENTED, "toTime"); + throw makeException(expr, I18nConstants.FHIRPATH_NOT_IMPLEMENTED, "toTime"); } - private List funcToDecimal(ExecutionContext context, List focus, ExpressionNode exp) { + private List funcToDecimal(ExecutionContext context, List focus, ExpressionNode expr) { String s = convertToString(focus); List result = new ArrayList(); if (Utilities.isDecimal(s, true)) { @@ -4152,7 +4158,7 @@ public class FHIRPathEngine { private List funcIif(ExecutionContext context, List focus, ExpressionNode exp) throws FHIRException { List n1 = execute(context, focus, exp.getParameters().get(0), true); - Equality v = asBool(n1); + Equality v = asBool(n1, exp); if (v == Equality.True) { return execute(context, focus, exp.getParameters().get(1), true); @@ -4227,28 +4233,28 @@ public class FHIRPathEngine { } - private List funcSingle(ExecutionContext context, List focus, ExpressionNode exp) throws PathEngineException { + private List funcSingle(ExecutionContext context, List focus, ExpressionNode expr) throws PathEngineException { if (focus.size() == 1) { return focus; } - throw makeException(I18nConstants.FHIRPATH_NO_COLLECTION, "single", focus.size()); + throw makeException(expr, I18nConstants.FHIRPATH_NO_COLLECTION, "single", focus.size()); } - private List funcIs(ExecutionContext context, List focus, ExpressionNode exp) throws PathEngineException { + private List funcIs(ExecutionContext context, List focus, ExpressionNode expr) throws PathEngineException { if (focus.size() == 0 || focus.size() > 1) { return makeNull(); } String ns = null; String n = null; - ExpressionNode texp = exp.getParameters().get(0); + ExpressionNode texp = expr.getParameters().get(0); if (texp.getKind() != Kind.Name) { - throw makeException(I18nConstants.FHIRPATH_PARAM_WRONG, texp.getKind(), "0", "is"); + throw makeException(expr, I18nConstants.FHIRPATH_PARAM_WRONG, texp.getKind(), "0", "is"); } if (texp.getInner() != null) { if (texp.getInner().getKind() != Kind.Name) { - throw makeException(I18nConstants.FHIRPATH_PARAM_WRONG, texp.getKind(), "1", "is"); + throw makeException(expr, I18nConstants.FHIRPATH_PARAM_WRONG, texp.getKind(), "1", "is"); } ns = texp.getName(); n = texp.getInner().getName(); @@ -4284,13 +4290,13 @@ public class FHIRPathEngine { } - private List funcAs(ExecutionContext context, List focus, ExpressionNode exp) { + private List funcAs(ExecutionContext context, List focus, ExpressionNode expr) { List result = new ArrayList(); String tn; - if (exp.getParameters().get(0).getInner() != null) { - tn = exp.getParameters().get(0).getName()+"."+exp.getParameters().get(0).getInner().getName(); + if (expr.getParameters().get(0).getInner() != null) { + tn = expr.getParameters().get(0).getName()+"."+expr.getParameters().get(0).getInner().getName(); } else { - tn = "FHIR."+exp.getParameters().get(0).getName(); + tn = "FHIR."+expr.getParameters().get(0).getName(); } for (Base b : focus) { if (tn.startsWith("System.")) { @@ -4436,7 +4442,7 @@ public class FHIRPathEngine { if (exp.getParameters().size() == 1) { pc.clear(); pc.add(f); - Equality v = asBool(execute(changeThis(context, f), pc, exp.getParameters().get(0), true)); + Equality v = asBool(execute(changeThis(context, f), pc, exp.getParameters().get(0), true), exp); if (v == Equality.True) { empty = false; } @@ -4531,7 +4537,7 @@ public class FHIRPathEngine { pc.clear(); pc.add(item); List res = execute(context, pc, exp.getParameters().get(0), true); - Equality v = asBool(res); + Equality v = asBool(res, exp); if (v != Equality.False) { all = false; break; @@ -4565,7 +4571,7 @@ public class FHIRPathEngine { pc.clear(); pc.add(item); List res = execute(context, pc, exp.getParameters().get(0), true); - Equality v = asBool(res); + Equality v = asBool(res, exp); if (v == Equality.False) { any = true; break; @@ -4599,7 +4605,7 @@ public class FHIRPathEngine { pc.clear(); pc.add(item); List res = execute(context, pc, exp.getParameters().get(0), true); - Equality v = asBool(res); + Equality v = asBool(res, exp); if (v != Equality.True) { all = false; break; @@ -4632,7 +4638,7 @@ public class FHIRPathEngine { pc.clear(); pc.add(item); List res = execute(context, pc, exp.getParameters().get(0), true); - Equality v = asBool(res); + Equality v = asBool(res, exp); if (v == Equality.True) { any = true; break; @@ -4673,12 +4679,12 @@ public class FHIRPathEngine { return focus; } - private List funcCheck(ExecutionContext context, List focus, ExpressionNode exp) throws FHIRException { - List n1 = execute(context, focus, exp.getParameters().get(0), true); + private List funcCheck(ExecutionContext context, List focus, ExpressionNode expr) throws FHIRException { + List n1 = execute(context, focus, expr.getParameters().get(0), true); if (!convertToBoolean(n1)) { - List n2 = execute(context, focus, exp.getParameters().get(1), true); + List n2 = execute(context, focus, expr.getParameters().get(1), true); String name = n2.get(0).primitiveValue(); - throw makeException(I18nConstants.FHIRPATH_CHECK_FAILED, name); + throw makeException(expr, I18nConstants.FHIRPATH_CHECK_FAILED, name); } return focus; } @@ -4940,15 +4946,15 @@ public class FHIRPathEngine { return result; } - private List funcConformsTo(ExecutionContext context, List focus, ExpressionNode exp) throws FHIRException { + private List funcConformsTo(ExecutionContext context, List focus, ExpressionNode expr) throws FHIRException { if (hostServices == null) { - throw makeException(I18nConstants.FHIRPATH_HO_HOST_SERVICES, "conformsTo"); + throw makeException(expr, I18nConstants.FHIRPATH_HO_HOST_SERVICES, "conformsTo"); } List result = new ArrayList(); if (focus.size() != 1) { result.add(new BooleanType(false).noExtensions()); } else { - String url = convertToString(execute(context, focus, exp.getParameters().get(0), true)); + String url = convertToString(execute(context, focus, expr.getParameters().get(0), true)); result.add(new BooleanType(hostServices.conformsToProfile(context.appInfo, focus.get(0), url)).noExtensions()); } return result; @@ -5111,7 +5117,7 @@ public class FHIRPathEngine { for (Base item : focus) { pc.clear(); pc.add(item); - Equality v = asBool(execute(changeThis(context, item), pc, exp.getParameters().get(0), true)); + Equality v = asBool(execute(changeThis(context, item), pc, exp.getParameters().get(0), true), exp); if (v == Equality.True) { result.add(item); } @@ -5148,7 +5154,7 @@ public class FHIRPathEngine { private List funcNot(ExecutionContext context, List focus, ExpressionNode exp) throws PathEngineException { List result = new ArrayList(); - Equality v = asBool(focus); + Equality v = asBool(focus, exp); if (v != Equality.Null) { result.add(new BooleanType(v != Equality.True)); } @@ -5172,9 +5178,9 @@ public class FHIRPathEngine { } - private void getChildTypesByName(String type, String name, TypeDetails result) throws PathEngineException, DefinitionException { + private void getChildTypesByName(String type, String name, TypeDetails result, ExpressionNode expr) throws PathEngineException, DefinitionException { if (Utilities.noString(type)) { - throw makeException(I18nConstants.FHIRPATH_NO_TYPE, "", "getChildTypesByName"); + throw makeException(expr, I18nConstants.FHIRPATH_NO_TYPE, "", "getChildTypesByName"); } if (type.equals("http://hl7.org/fhir/StructureDefinition/xhtml")) { return; @@ -5197,24 +5203,24 @@ public class FHIRPathEngine { String tail = ""; StructureDefinition sd = worker.fetchResource(StructureDefinition.class, url); if (sd == null) { - throw makeException(I18nConstants.FHIRPATH_NO_TYPE, url, "getChildTypesByName"); + throw makeException(expr, I18nConstants.FHIRPATH_NO_TYPE, url, "getChildTypesByName"); } List sdl = new ArrayList(); ElementDefinitionMatch m = null; if (type.contains("#")) - m = getElementDefinition(sd, type.substring(type.indexOf("#")+1), false); + m = getElementDefinition(sd, type.substring(type.indexOf("#")+1), false, expr); if (m != null && hasDataType(m.definition)) { if (m.fixedType != null) { StructureDefinition dt = worker.fetchResource(StructureDefinition.class, ProfileUtilities.sdNs(m.fixedType, worker.getOverrideVersionNs())); if (dt == null) { - throw makeException(I18nConstants.FHIRPATH_NO_TYPE, ProfileUtilities.sdNs(m.fixedType, worker.getOverrideVersionNs()), "getChildTypesByName"); + throw makeException(expr, I18nConstants.FHIRPATH_NO_TYPE, ProfileUtilities.sdNs(m.fixedType, worker.getOverrideVersionNs()), "getChildTypesByName"); } sdl.add(dt); } else for (TypeRefComponent t : m.definition.getType()) { StructureDefinition dt = worker.fetchResource(StructureDefinition.class, ProfileUtilities.sdNs(t.getCode(), worker.getOverrideVersionNs())); if (dt == null) { - throw makeException(I18nConstants.FHIRPATH_NO_TYPE, ProfileUtilities.sdNs(t.getCode(), worker.getOverrideVersionNs()), "getChildTypesByName"); + throw makeException(expr, I18nConstants.FHIRPATH_NO_TYPE, ProfileUtilities.sdNs(t.getCode(), worker.getOverrideVersionNs()), "getChildTypesByName"); } sdl.add(dt); } @@ -5243,11 +5249,11 @@ public class FHIRPathEngine { if (t.getCode().equals("Resource")) { for (String rn : worker.getResourceNames()) { if (!result.hasType(worker, rn)) { - getChildTypesByName(result.addType(rn), "**", result); + getChildTypesByName(result.addType(rn), "**", result, expr); } } } else if (!result.hasType(worker, tn)) { - getChildTypesByName(result.addType(tn), "**", result); + getChildTypesByName(result.addType(tn), "**", result, expr); } } } @@ -5271,7 +5277,7 @@ public class FHIRPathEngine { } else { path = sdi.getSnapshot().getElement().get(0).getPath()+tail+"."+name; - ElementDefinitionMatch ed = getElementDefinition(sdi, path, isAllowPolymorphicNames()); + ElementDefinitionMatch ed = getElementDefinition(sdi, path, isAllowPolymorphicNames(), expr); if (ed != null) { if (!Utilities.noString(ed.getFixedType())) result.addType(ed.getFixedType()); @@ -5329,7 +5335,7 @@ public class FHIRPathEngine { } - private ElementDefinitionMatch getElementDefinition(StructureDefinition sd, String path, boolean allowTypedName) throws PathEngineException { + private ElementDefinitionMatch getElementDefinition(StructureDefinition sd, String path, boolean allowTypedName, ExpressionNode expr) throws PathEngineException { for (ElementDefinition ed : sd.getSnapshot().getElement()) { if (ed.getPath().equals(path)) { if (ed.hasContentReference()) { @@ -5356,13 +5362,13 @@ public class FHIRPathEngine { } StructureDefinition nsd = worker.fetchResource(StructureDefinition.class, ProfileUtilities.sdNs(ed.getType().get(0).getCode(), worker.getOverrideVersionNs())); if (nsd == null) { - throw makeException(I18nConstants.FHIRPATH_NO_TYPE, ed.getType().get(0).getCode(), "getElementDefinition"); + throw makeException(expr, I18nConstants.FHIRPATH_NO_TYPE, ed.getType().get(0).getCode(), "getElementDefinition"); } - return getElementDefinition(nsd, nsd.getId()+path.substring(ed.getPath().length()), allowTypedName); + return getElementDefinition(nsd, nsd.getId()+path.substring(ed.getPath().length()), allowTypedName, expr); } if (ed.hasContentReference() && path.startsWith(ed.getPath()+".")) { ElementDefinitionMatch m = getElementDefinitionById(sd, ed.getContentReference()); - return getElementDefinition(sd, m.definition.getPath()+path.substring(ed.getPath().length()), allowTypedName); + return getElementDefinition(sd, m.definition.getPath()+path.substring(ed.getPath().length()), allowTypedName, expr); } } return null; @@ -5430,7 +5436,7 @@ public class FHIRPathEngine { if (element.hasSlicing()) { ElementDefinition slice = pickMandatorySlice(sd, element); if (slice == null) { - throw makeException(I18nConstants.FHIRPATH_DISCRIMINATOR_NAME_ALREADY_SLICED, element.getId()); + throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_NAME_ALREADY_SLICED, element.getId()); } element = slice; } @@ -5443,9 +5449,9 @@ public class FHIRPathEngine { // if that's empty, get the children of the type if (childDefinitions.isEmpty()) { - sd = fetchStructureByType(element); + sd = fetchStructureByType(element, expr); if (sd == null) { - throw makeException(I18nConstants.FHIRPATH_DISCRIMINATOR_THIS_CANNOT_FIND, element.getType().get(0).getProfile(), element.getId()); + throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_THIS_CANNOT_FIND, element.getType().get(0).getProfile(), element.getId()); } childDefinitions = profileUtilities.getChildMap(sd, sd.getSnapshot().getElementFirstRep()); } @@ -5459,20 +5465,20 @@ public class FHIRPathEngine { } else if (expr.getKind() == Kind.Function) { if ("resolve".equals(expr.getName())) { if (!element.hasType()) { - throw makeException(I18nConstants.FHIRPATH_DISCRIMINATOR_RESOLVE_NO_TYPE, element.getId()); + throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_RESOLVE_NO_TYPE, element.getId()); } if (element.getType().size() > 1) { - throw makeException(I18nConstants.FHIRPATH_DISCRIMINATOR_RESOLVE_MULTIPLE_TYPES, element.getId()); + throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_RESOLVE_MULTIPLE_TYPES, element.getId()); } if (!element.getType().get(0).hasTarget()) { - throw makeException(I18nConstants.FHIRPATH_DISCRIMINATOR_RESOLVE_NOT_REFERENCE, element.getId(), element.getType().get(0).getCode()+")"); + throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_RESOLVE_NOT_REFERENCE, element.getId(), element.getType().get(0).getCode()+")"); } if (element.getType().get(0).getTargetProfile().size() > 1) { - throw makeException(I18nConstants.FHIRPATH_RESOLVE_DISCRIMINATOR_NO_TARGET, element.getId()); + throw makeException(expr, I18nConstants.FHIRPATH_RESOLVE_DISCRIMINATOR_NO_TARGET, element.getId()); } sd = worker.fetchResource(StructureDefinition.class, element.getType().get(0).getTargetProfile().get(0).getValue()); if (sd == null) { - throw makeException(I18nConstants.FHIRPATH_RESOLVE_DISCRIMINATOR_CANT_FIND, element.getType().get(0).getTargetProfile(), element.getId()); + throw makeException(expr, I18nConstants.FHIRPATH_RESOLVE_DISCRIMINATOR_CANT_FIND, element.getType().get(0).getTargetProfile(), element.getId()); } focus = sd.getSnapshot().getElementFirstRep(); } else if ("extension".equals(expr.getName())) { @@ -5496,13 +5502,13 @@ public class FHIRPathEngine { } } else if ("ofType".equals(expr.getName())) { if (!element.hasType()) { - throw makeException(I18nConstants.FHIRPATH_DISCRIMINATOR_TYPE_NONE, element.getId()); + throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_TYPE_NONE, element.getId()); } if (element.getType().size() > 1) { - throw makeException(I18nConstants.FHIRPATH_DISCRIMINATOR_TYPE_MULTIPLE, element.getId()); + throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_TYPE_MULTIPLE, element.getId()); } if (!element.getType().get(0).hasCode()) { - throw makeException(I18nConstants.FHIRPATH_DISCRIMINATOR_NO_CODE, element.getId()); + throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_NO_CODE, element.getId()); } String atn = element.getType().get(0).getCode(); String stn = expr.getParameters().get(0).getName(); @@ -5511,19 +5517,19 @@ public class FHIRPathEngine { focus = element; } } else { - throw makeException(I18nConstants.FHIRPATH_DISCRIMINATOR_BAD_NAME, expr.getName()); + throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_BAD_NAME, expr.getName()); } } else if (expr.getKind() == Kind.Group) { - throw makeException(I18nConstants.FHIRPATH_DISCRIMINATOR_BAD_SYNTAX_GROUP); + throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_BAD_SYNTAX_GROUP); } else if (expr.getKind() == Kind.Constant) { - throw makeException(I18nConstants.FHIRPATH_DISCRIMINATOR_BAD_SYNTAX_CONST); + throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_BAD_SYNTAX_CONST); } if (focus == null) { if (okToNotResolve) { return null; } else { - throw makeException(I18nConstants.FHIRPATH_DISCRIMINATOR_CANT_FIND, expr.toString()); + throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_CANT_FIND, expr.toString()); } } else if (expr.getInner() == null) { return focus; @@ -5543,15 +5549,15 @@ public class FHIRPathEngine { } - private StructureDefinition fetchStructureByType(ElementDefinition ed) throws DefinitionException { + private StructureDefinition fetchStructureByType(ElementDefinition ed, ExpressionNode expr) throws DefinitionException { if (ed.getType().size() == 0) { - throw makeException(I18nConstants.FHIRPATH_DISCRIMINATOR_NOTYPE, ed.getId()); + throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_NOTYPE, ed.getId()); } if (ed.getType().size() > 1) { - throw makeException(I18nConstants.FHIRPATH_DISCRIMINATOR_MULTIPLE_TYPES, ed.getId()); + throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_MULTIPLE_TYPES, ed.getId()); } if (ed.getType().get(0).getProfile().size() > 1) { - throw makeException(I18nConstants.FHIRPATH_DISCRIMINATOR_MULTIPLE_PROFILES, ed.getId()); + throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_MULTIPLE_PROFILES, ed.getId()); } if (ed.getType().get(0).hasProfile()) { return worker.fetchResource(StructureDefinition.class, ed.getType().get(0).getProfile().get(0).getValue()); @@ -5579,7 +5585,7 @@ public class FHIRPathEngine { return path.substring(path.lastIndexOf(".") + 1); } - private Equality asBool(List items) throws PathEngineException { + private Equality asBool(List items, ExpressionNode expr) throws PathEngineException { if (items.size() == 0) { return Equality.Null; } else if (items.size() == 1 && items.get(0).isBooleanPrimitive()) { @@ -5587,7 +5593,7 @@ public class FHIRPathEngine { } else if (items.size() == 1) { return Equality.True; } else { - throw makeException(I18nConstants.FHIRPATH_UNABLE_BOOLEAN, convertToString(items)); + throw makeException(expr, I18nConstants.FHIRPATH_UNABLE_BOOLEAN, convertToString(items)); } } diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/FHIRPathTests.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/FHIRPathTests.java index 322027805..22b3e3e21 100644 --- a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/FHIRPathTests.java +++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/FHIRPathTests.java @@ -176,6 +176,7 @@ public class FHIRPathTests { node = fp.parse(expression); Assertions.assertTrue(fail != TestResultType.SYNTAX, String.format("Expected exception didn't occur parsing %s", expression)); } catch (Exception e) { + System.out.println("Parsing Error: "+e.getMessage()); Assertions.assertTrue(fail == TestResultType.SYNTAX, String.format("Unexpected exception parsing %s: " + e.getMessage(), expression)); } @@ -193,6 +194,7 @@ public class FHIRPathTests { } Assertions.assertTrue(fail != TestResultType.SEMANTICS, String.format("Expected exception didn't occur checking %s", expression)); } catch (Exception e) { + System.out.println("Checking Error: "+e.getMessage()); Assertions.assertTrue(fail == TestResultType.SEMANTICS, String.format("Unexpected exception checking %s: " + e.getMessage(), expression)); node = null; } @@ -203,6 +205,7 @@ public class FHIRPathTests { outcome = fp.evaluate(res, node); Assertions.assertTrue(fail == TestResultType.OK, String.format("Expected exception didn't occur executing %s", expression)); } catch (Exception e) { + System.out.println("Execution Error: "+e.getMessage()); Assertions.assertTrue(fail == TestResultType.EXECUTION, String.format("Unexpected exception executing %s: " + e.getMessage(), expression)); node = null; } diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/exceptions/PathEngineException.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/exceptions/PathEngineException.java index 1eb33bdeb..b26a5ce16 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/exceptions/PathEngineException.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/exceptions/PathEngineException.java @@ -1,5 +1,8 @@ package org.hl7.fhir.exceptions; +import org.hl7.fhir.utilities.SourceLocation; +import org.hl7.fhir.utilities.Utilities; + /* Copyright (c) 2011+, HL7, Inc. All rights reserved. @@ -33,20 +36,62 @@ package org.hl7.fhir.exceptions; public class PathEngineException extends FHIRException { + private static final long serialVersionUID = 31969342112856390L; + private SourceLocation location; + private String expression; + public PathEngineException() { super(); } - public PathEngineException(String message, Throwable cause) { - super(message, cause); - } + public PathEngineException(String message, Throwable cause) { + super(message, cause); + } - public PathEngineException(String message) { - super(message); - } + public PathEngineException(String message) { + super(message); + } - public PathEngineException(Throwable cause) { + public PathEngineException(String message, SourceLocation location, String expression, Throwable cause) { + super(message+rep(location, expression), cause); + } + + public PathEngineException(String message, SourceLocation location, String expression) { + super(message+rep(location, expression)); + } + + private static String rep(SourceLocation loc, String expr) { + if (loc != null) { + if (loc.getLine() == 1) { + return " (@char "+loc.getColumn()+")"; + } else { + return " (@line "+loc.getLine()+" char "+loc.getColumn()+")"; + } + } else if (Utilities.noString(expr)) { // can happen in some contexts... + return " (@~"+expr+")"; + } else { + return ""; + } + } + + public PathEngineException(Throwable cause) { super(cause); } + public String getExpression() { + return expression; + } + + public void setExpression(String expression) { + this.expression = expression; + } + + public SourceLocation getLocation() { + return location; + } + + public void setLocation(SourceLocation location) { + this.location = location; + } + } \ No newline at end of file diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/SourceLocation.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/SourceLocation.java new file mode 100644 index 000000000..5ed864765 --- /dev/null +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/SourceLocation.java @@ -0,0 +1,27 @@ +package org.hl7.fhir.utilities; + +public class SourceLocation { + private int line; + private int column; + public SourceLocation(int line, int column) { + super(); + this.line = line; + this.column = column; + } + public int getLine() { + return line; + } + public int getColumn() { + return column; + } + public void setLine(int line) { + this.line = line; + } + public void setColumn(int column) { + this.column = column; + } + + public String toString() { + return Integer.toString(line)+", "+Integer.toString(column); + } +} From 75d5939227b4628566ff6f9cfc4d4e9b4d9032a2 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Wed, 30 Sep 2020 23:27:23 +1000 Subject: [PATCH 65/73] prepare for 5.1.16 release (#358) * Ensure "I" flag in profile table representation is not used for underlying infrastructural constraints that exist everywhere * render multiple values for properties if they exist * fix for npe * fix for use of "current" as version * fix bad package URLs as they are loaded * RELEASE_NOTES.md * Add rendering for must support on types, profiles, targets * Add new validation for must-support on types / profiles / targets + improve extension validation * add when rendering turtle to HTML * RELEASE_NOTES.md * fix notes * fix rendering problems with languages in value sets * Change warnings about invalid codes to hints in retired value sets * Fix bugs loading content to validate from hapi servers * Fix FHIRPath engine for updated tests for date addition/subtraction * fix questionnaire mode support for validator * rename org.hl7.fhir.utilities.cache to org.hl7.fhir.utilities.npm * update to POM * refactor FHIRPath to report error locations for run time errors --- RELEASE_NOTES.md | 7 + .../ExtensionDefinitionGenerator.java | 8 +- .../fhir/convertors/loaders/BaseLoaderR3.java | 2 +- .../fhir/convertors/loaders/BaseLoaderR4.java | 2 +- .../fhir/convertors/loaders/BaseLoaderR5.java | 2 +- .../loaders/R2016MayToR5Loader.java | 2 +- .../fhir/convertors/loaders/R2ToR5Loader.java | 2 +- .../fhir/convertors/loaders/R3ToR5Loader.java | 2 +- .../fhir/convertors/loaders/R4ToR5Loader.java | 2 +- .../fhir/convertors/loaders/R5ToR5Loader.java | 2 +- .../fhir/convertors/misc/NUCCConvertor.java | 78 +- .../misc/NpmPackageVersionConverter.java | 2 +- .../misc/OIDBasedValueSetImporter.java | 6 +- .../convertors/misc/PhinVadsImporter.java | 6 +- .../convertors/misc/XMLPackageConvertor.java | 2 +- .../dstu3/context/SimpleWorkerContext.java | 2 +- .../fhir/r4/context/SimpleWorkerContext.java | 2 +- .../hl7/fhir/r4/model/BaseDateTimeType.java | 5 + .../org/hl7/fhir/r4/model/CodeSystem.java | 25 + .../org/hl7/fhir/r4/model/ExpressionNode.java | 26 +- .../org/hl7/fhir/r4/model/PrimitiveType.java | 3 + .../r4/terminologies/CodeSystemUtilities.java | 2 +- .../fhir/r4/test/utils/TestingUtilities.java | 4 +- .../java/org/hl7/fhir/r4/utils/FHIRLexer.java | 2 +- .../org/hl7/fhir/r4/utils/FHIRPathEngine.java | 555 +++++++------ .../fhir/r4/utils/NPMPackageGenerator.java | 4 +- .../hl7/fhir/r4/test/CDARoundTripTests.java | 4 +- .../org/hl7/fhir/r4/test/FHIRPathTests.java | 2 +- .../r5/context/CanonicalResourceManager.java | 1 + .../hl7/fhir/r5/context/IWorkerContext.java | 4 +- .../fhir/r5/context/SimpleWorkerContext.java | 8 +- .../hl7/fhir/r5/model/BaseDateTimeType.java | 5 + .../org/hl7/fhir/r5/model/ExpressionNode.java | 25 +- .../org/hl7/fhir/r5/model/PrimitiveType.java | 4 + .../fhir/r5/renderers/ValueSetRenderer.java | 10 +- .../fhir/r5/test/utils/TestingUtilities.java | 4 +- .../java/org/hl7/fhir/r5/utils/FHIRLexer.java | 2 +- .../org/hl7/fhir/r5/utils/FHIRPathEngine.java | 760 ++++++++++-------- .../fhir/r5/utils/NPMPackageGenerator.java | 6 +- .../hl7/fhir/r5/test/CDARoundTripTests.java | 4 +- .../org/hl7/fhir/r5/test/FHIRPathTests.java | 9 +- .../org/hl7/fhir/r5/test/NpmPackageTests.java | 2 +- .../org/hl7/fhir/r5/test/ParsingTests.java | 6 +- .../fhir/r5/test/SnapShotGenerationTests.java | 6 +- .../r5/test/StructureMapUtilitiesTest.java | 4 +- .../org/hl7/fhir/r5/test/XmlParserTests.java | 4 +- .../fhir/exceptions/PathEngineException.java | 59 +- .../hl7/fhir/utilities/SourceLocation.java | 27 + .../hl7/fhir/utilities/VersionUtilities.java | 2 +- .../BasePackageCacheManager.java | 2 +- .../{cache => npm}/CachingPackageClient.java | 2 +- .../FilesystemPackageCacheManager.java | 4 +- .../{cache => npm}/IPackageCacheManager.java | 2 +- .../utilities/{cache => npm}/NpmPackage.java | 6 +- .../NpmPackageIndexBuilder.java | 2 +- .../{cache => npm}/PackageClient.java | 2 +- .../{cache => npm}/PackageGenerator.java | 2 +- .../{cache => npm}/PackageHacker.java | 2 +- .../{cache => npm}/ToolsVersion.java | 2 +- .../src/main/resources/Messages.properties | 12 +- .../tests/CachingPackageClientTests.java | 4 +- .../utilities/tests/PackageCacheTests.java | 6 +- .../hl7/fhir/validation/BaseValidator.java | 15 + .../hl7/fhir/validation/ValidationEngine.java | 98 ++- .../org/hl7/fhir/validation/Validator.java | 2 + .../fhir/validation/cli/model/CliContext.java | 29 +- .../services/StandAloneValidatorFetcher.java | 6 +- .../cli/services/ValidationService.java | 2 +- .../fhir/validation/cli/utils/Display.java | 4 +- .../hl7/fhir/validation/cli/utils/Params.java | 6 +- .../instance/InstanceValidator.java | 14 +- .../instance/type/QuestionnaireValidator.java | 18 +- .../instance/type/ValueSetValidator.java | 14 +- .../validation/packages/PackageValidator.java | 10 +- .../comparison/tests/ComparisonTests.java | 6 +- .../conversion/tests/R3R4ConversionTests.java | 4 +- .../conversion/tests/UtilitiesXTests.java | 5 +- pom.xml | 2 +- 78 files changed, 1143 insertions(+), 853 deletions(-) create mode 100644 org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/SourceLocation.java rename org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/{cache => npm}/BasePackageCacheManager.java (99%) rename org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/{cache => npm}/CachingPackageClient.java (97%) rename org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/{cache => npm}/FilesystemPackageCacheManager.java (99%) rename org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/{cache => npm}/IPackageCacheManager.java (94%) rename org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/{cache => npm}/NpmPackage.java (99%) rename org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/{cache => npm}/NpmPackageIndexBuilder.java (97%) rename org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/{cache => npm}/PackageClient.java (99%) rename org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/{cache => npm}/PackageGenerator.java (99%) rename org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/{cache => npm}/PackageHacker.java (97%) rename org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/{cache => npm}/ToolsVersion.java (97%) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index e69de29bb..e97786dae 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -0,0 +1,7 @@ +Validator: +* Add date addition/subtraction to FHIRPath +* Fix questionnaire mode parameter support for validator +* add extra debugging when valdiator can't fetch content to validate + +Other code changes: +* rename org.hl7.fhir.utilities.cache to org.hl7.fhir.utilities.npm diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/ExtensionDefinitionGenerator.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/ExtensionDefinitionGenerator.java index a5f2d838f..47a597ee3 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/ExtensionDefinitionGenerator.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/ExtensionDefinitionGenerator.java @@ -65,10 +65,10 @@ import org.hl7.fhir.r4.model.UriType; import org.hl7.fhir.r4.utils.NPMPackageGenerator; import org.hl7.fhir.r4.utils.NPMPackageGenerator.Category; import org.hl7.fhir.utilities.Utilities; -import org.hl7.fhir.utilities.cache.NpmPackage; -import org.hl7.fhir.utilities.cache.FilesystemPackageCacheManager; -import org.hl7.fhir.utilities.cache.PackageGenerator.PackageType; -import org.hl7.fhir.utilities.cache.ToolsVersion; +import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; +import org.hl7.fhir.utilities.npm.NpmPackage; +import org.hl7.fhir.utilities.npm.ToolsVersion; +import org.hl7.fhir.utilities.npm.PackageGenerator.PackageType; import com.google.gson.JsonArray; import com.google.gson.JsonObject; diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/BaseLoaderR3.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/BaseLoaderR3.java index 7b18144bb..758f97223 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/BaseLoaderR3.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/BaseLoaderR3.java @@ -5,7 +5,7 @@ import org.hl7.fhir.dstu3.model.Bundle; import org.hl7.fhir.dstu3.model.ElementDefinition; import org.hl7.fhir.dstu3.model.Resource; import org.hl7.fhir.dstu3.model.StructureDefinition; -import org.hl7.fhir.utilities.cache.NpmPackage; +import org.hl7.fhir.utilities.npm.NpmPackage; import java.util.ArrayList; import java.util.List; diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/BaseLoaderR4.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/BaseLoaderR4.java index 06c9aefad..8b0ed82a7 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/BaseLoaderR4.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/BaseLoaderR4.java @@ -6,7 +6,7 @@ import org.hl7.fhir.r4.model.CanonicalType; import org.hl7.fhir.r4.model.ElementDefinition; import org.hl7.fhir.r4.model.Resource; import org.hl7.fhir.r4.model.StructureDefinition; -import org.hl7.fhir.utilities.cache.NpmPackage; +import org.hl7.fhir.utilities.npm.NpmPackage; import java.util.ArrayList; import java.util.List; diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/BaseLoaderR5.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/BaseLoaderR5.java index f051fe763..43642a52c 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/BaseLoaderR5.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/BaseLoaderR5.java @@ -8,7 +8,7 @@ import org.hl7.fhir.r5.model.ElementDefinition; import org.hl7.fhir.r5.model.Resource; import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.utilities.VersionUtilities; -import org.hl7.fhir.utilities.cache.NpmPackage; +import org.hl7.fhir.utilities.npm.NpmPackage; import com.google.gson.JsonSyntaxException; diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/R2016MayToR5Loader.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/R2016MayToR5Loader.java index 054ad92fd..4aa7b132a 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/R2016MayToR5Loader.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/R2016MayToR5Loader.java @@ -55,9 +55,9 @@ import org.hl7.fhir.r5.model.CodeSystem; import org.hl7.fhir.r5.model.ElementDefinition; import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind; +import org.hl7.fhir.utilities.npm.NpmPackage; import org.hl7.fhir.r5.model.UriType; import org.hl7.fhir.r5.model.ValueSet; -import org.hl7.fhir.utilities.cache.NpmPackage; import com.google.gson.JsonSyntaxException; diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/R2ToR5Loader.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/R2ToR5Loader.java index a2af79bfe..07f64c869 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/R2ToR5Loader.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/R2ToR5Loader.java @@ -56,9 +56,9 @@ import org.hl7.fhir.r5.model.CodeSystem; import org.hl7.fhir.r5.model.ElementDefinition; import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind; +import org.hl7.fhir.utilities.npm.NpmPackage; import org.hl7.fhir.r5.model.UriType; import org.hl7.fhir.r5.model.ValueSet; -import org.hl7.fhir.utilities.cache.NpmPackage; import com.google.gson.JsonSyntaxException; diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/R3ToR5Loader.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/R3ToR5Loader.java index 24439f069..07feac9ab 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/R3ToR5Loader.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/R3ToR5Loader.java @@ -56,9 +56,9 @@ import org.hl7.fhir.r5.model.ElementDefinition; import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent; import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind; +import org.hl7.fhir.utilities.npm.NpmPackage; import org.hl7.fhir.r5.model.UriType; import org.hl7.fhir.r5.model.ValueSet; -import org.hl7.fhir.utilities.cache.NpmPackage; import com.google.gson.JsonSyntaxException; diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/R4ToR5Loader.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/R4ToR5Loader.java index 8df1eef65..fa8af1b5f 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/R4ToR5Loader.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/R4ToR5Loader.java @@ -56,9 +56,9 @@ import org.hl7.fhir.r5.model.ElementDefinition; import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent; import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind; +import org.hl7.fhir.utilities.npm.NpmPackage; import org.hl7.fhir.r5.model.UriType; import org.hl7.fhir.r5.model.ValueSet; -import org.hl7.fhir.utilities.cache.NpmPackage; import com.google.gson.JsonSyntaxException; diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/R5ToR5Loader.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/R5ToR5Loader.java index dd67566e1..a71cb3705 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/R5ToR5Loader.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/R5ToR5Loader.java @@ -55,9 +55,9 @@ import org.hl7.fhir.r5.model.ElementDefinition; import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent; import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind; +import org.hl7.fhir.utilities.npm.NpmPackage; import org.hl7.fhir.r5.model.UriType; import org.hl7.fhir.r5.model.ValueSet; -import org.hl7.fhir.utilities.cache.NpmPackage; import com.google.gson.JsonSyntaxException; diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/NUCCConvertor.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/NUCCConvertor.java index 777768c59..7c677c3da 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/NUCCConvertor.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/NUCCConvertor.java @@ -35,30 +35,31 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; -import org.hl7.fhir.dstu3.formats.IParser.OutputStyle; -import org.hl7.fhir.dstu3.formats.XmlParser; -import org.hl7.fhir.dstu3.model.CodeSystem; -import org.hl7.fhir.dstu3.model.CodeSystem.CodeSystemContentMode; -import org.hl7.fhir.dstu3.model.CodeSystem.CodeSystemHierarchyMeaning; -import org.hl7.fhir.dstu3.model.CodeSystem.ConceptDefinitionComponent; -import org.hl7.fhir.dstu3.model.DateTimeType; -import org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus; -import org.hl7.fhir.dstu3.terminologies.CodeSystemUtilities; -import org.hl7.fhir.dstu3.utils.ToolingExtensions; +import org.hl7.fhir.r4.formats.IParser.OutputStyle; +import org.hl7.fhir.r4.formats.XmlParser; +import org.hl7.fhir.r4.model.CodeSystem; +import org.hl7.fhir.r4.model.CodeSystem.CodeSystemContentMode; +import org.hl7.fhir.r4.model.CodeSystem.CodeSystemHierarchyMeaning; +import org.hl7.fhir.r4.model.CodeSystem.ConceptDefinitionComponent; +import org.hl7.fhir.r4.model.CodeSystem.PropertyType; +import org.hl7.fhir.r4.model.DateTimeType; +import org.hl7.fhir.r4.model.Enumerations.PublicationStatus; +import org.hl7.fhir.r4.model.StringType; +import org.hl7.fhir.r4.terminologies.CodeSystemUtilities; +import org.hl7.fhir.r4.utils.ToolingExtensions; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRFormatError; +import org.hl7.fhir.r4.formats.JsonParser; import org.hl7.fhir.utilities.CSVReader; import org.hl7.fhir.utilities.Utilities; public class NUCCConvertor { - private String[] last = new String[2]; - private ConceptDefinitionComponent[] concepts = new ConceptDefinitionComponent[2]; public static void main(String[] args) throws Exception { new NUCCConvertor().execute(); } - public void execute() throws IOException, FHIRException { + public void execute() throws IOException, FHIRException { CSVReader csv = new CSVReader(new FileInputStream("c:\\temp\\nucc.csv")); CodeSystem cs = new CodeSystem(); cs.setId("nucc-provider-taxonomy"); @@ -66,50 +67,41 @@ public class NUCCConvertor { cs.setName("NUCC Provider Taxonomy"); cs.setDateElement(new DateTimeType()); cs.setDescription("The Health Care Provider Taxonomy code is a unique alphanumeric code, ten characters in length. The code set is structured into three distinct 'Levels' including Provider Type, Classification, and Area of Specialization"); - cs.setCopyright("See NUCC copyright statement"); + cs.setCopyright("Vendors must request a license to include this in a product per the following: 'Vendors interested in incorporating the Health Care Provider Taxonomy code set into their commercial products must complete the license request form found on the CSV page.' Using the form at the url listed. The preamble is reproduced below: http://www.nucc.org/index.php?option=com_content&view=article&id=111&Itemid=110"); cs.setStatus(PublicationStatus.ACTIVE); cs.setContent(CodeSystemContentMode.COMPLETE); cs.setExperimental(false); cs.setValueSet("http://hl7.org/fhir/ValueSet/nucc-provider-taxonomy"); cs.setHierarchyMeaning(CodeSystemHierarchyMeaning.CLASSIFIEDWITH); + cs.addProperty().setCode("grouping").setType(PropertyType.STRING).setDescription("A major grouping of service(s) or occupation(s) of health care providers. For example: Allopathic & Osteopathic Physicians, Dental Providers, Hospitals, etc"); + cs.addProperty().setCode("classification").setType(PropertyType.STRING).setDescription("A more specific service or occupation related to the Provider Grouping.e"); + cs.addProperty().setCode("specialization").setType(PropertyType.STRING).setDescription("A more specialized area of the Classification in which a provider chooses to practice or make services available."); csv.parseLine(); - while (csv.ready()) - { + while (csv.ready()) { String[] values = csv.parseLine(); processLine(cs, values); } csv.close(); - new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream("c:\\temp\\nucc.xml"), cs); + cs.sort(); + new JsonParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream("c:\\temp\\nucc.json"), cs); } private void processLine(CodeSystem cs, String[] values) throws FHIRFormatError { - if (!values[1].equals(last[0])) { - last[1] = ""; - last[0] = values[1]; - concepts[0] = new ConceptDefinitionComponent(); - cs.getConcept().add(concepts[0]); - concepts[0].setDisplay(values[1]); - concepts[0].setCode("base-"+Integer.toString(cs.getConcept().size())); - CodeSystemUtilities.setNotSelectable(cs, concepts[0]); + ConceptDefinitionComponent cc = new ConceptDefinitionComponent(); + cs.getConcept().add(cc); + cc.setCode(values[0]); + cc.setDisplay(values[4]); + if (!Utilities.noString(values[1])) { + cc.addProperty().setCode("grouping").setValue(new StringType(values[1])); } - if (!values[2].equals(last[1])) { - last[1] = values[2]; - concepts[1] = new ConceptDefinitionComponent(); - concepts[0].getConcept().add(concepts[1]); - concepts[1].setCode(values[0]); - concepts[1].setDisplay(values[2]); - concepts[1].setDefinition(values[4]); - if (values.length > 5 && !Utilities.noString(values[5])) - ToolingExtensions.addCSComment(concepts[1], values[5]); - } else if (!Utilities.noString(values[3])) { - ConceptDefinitionComponent cc = new ConceptDefinitionComponent(); - concepts[1].getConcept().add(cc); - cc.setCode(values[0]); - cc.setDisplay(values[3]); - cc.setDefinition(values[4]); - if (values.length > 5 && !Utilities.noString(values[5])) - ToolingExtensions.addCSComment(cc, values[5]); + if (!Utilities.noString(values[2])) { + cc.addProperty().setCode("classification").setValue(new StringType(values[2])); } + if (!Utilities.noString(values[3])) { + cc.addProperty().setCode("specialization").setValue(new StringType(values[3])); + } + if (values.length > 5 && !Utilities.noString(values[5])) + cc.setDefinition(values[5]); } - + } \ No newline at end of file diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/NpmPackageVersionConverter.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/NpmPackageVersionConverter.java index f5da11936..4f63e27fa 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/NpmPackageVersionConverter.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/NpmPackageVersionConverter.java @@ -33,9 +33,9 @@ import org.hl7.fhir.r4.model.CodeSystem; import org.hl7.fhir.r4.model.ValueSet; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.VersionUtilities; -import org.hl7.fhir.utilities.cache.NpmPackageIndexBuilder; import org.hl7.fhir.utilities.json.JSONUtil; import org.hl7.fhir.utilities.json.JsonTrackingParser; +import org.hl7.fhir.utilities.npm.NpmPackageIndexBuilder; import com.google.common.base.Charsets; import com.google.gson.JsonArray; diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/OIDBasedValueSetImporter.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/OIDBasedValueSetImporter.java index 020a643e2..87475bfc1 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/OIDBasedValueSetImporter.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/OIDBasedValueSetImporter.java @@ -12,9 +12,9 @@ import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.context.SimpleWorkerContext; import org.hl7.fhir.r5.model.ValueSet; import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent; -import org.hl7.fhir.utilities.cache.FilesystemPackageCacheManager; -import org.hl7.fhir.utilities.cache.NpmPackage; -import org.hl7.fhir.utilities.cache.ToolsVersion; +import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; +import org.hl7.fhir.utilities.npm.NpmPackage; +import org.hl7.fhir.utilities.npm.ToolsVersion; import org.w3c.dom.Document; public class OIDBasedValueSetImporter { diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/PhinVadsImporter.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/PhinVadsImporter.java index 1f9a3db56..deafaf349 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/PhinVadsImporter.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/PhinVadsImporter.java @@ -19,9 +19,9 @@ import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent; import org.hl7.fhir.utilities.CSVReader; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; -import org.hl7.fhir.utilities.cache.FilesystemPackageCacheManager; -import org.hl7.fhir.utilities.cache.NpmPackage; -import org.hl7.fhir.utilities.cache.ToolsVersion; +import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; +import org.hl7.fhir.utilities.npm.NpmPackage; +import org.hl7.fhir.utilities.npm.ToolsVersion; public class PhinVadsImporter extends OIDBasedValueSetImporter { diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/XMLPackageConvertor.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/XMLPackageConvertor.java index 67d0e97ac..c359c4d71 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/XMLPackageConvertor.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/XMLPackageConvertor.java @@ -6,7 +6,7 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.util.Map.Entry; -import org.hl7.fhir.utilities.cache.NpmPackage; +import org.hl7.fhir.utilities.npm.NpmPackage; import com.google.gson.JsonElement; import com.google.gson.JsonObject; diff --git a/org.hl7.fhir.dstu3/src/main/java/org/hl7/fhir/dstu3/context/SimpleWorkerContext.java b/org.hl7.fhir.dstu3/src/main/java/org/hl7/fhir/dstu3/context/SimpleWorkerContext.java index 18b4833e7..080ed1952 100644 --- a/org.hl7.fhir.dstu3/src/main/java/org/hl7/fhir/dstu3/context/SimpleWorkerContext.java +++ b/org.hl7.fhir.dstu3/src/main/java/org/hl7/fhir/dstu3/context/SimpleWorkerContext.java @@ -89,7 +89,7 @@ import org.hl7.fhir.exceptions.FHIRFormatError; import org.hl7.fhir.utilities.CSFileInputStream; import org.hl7.fhir.utilities.OIDUtils; import org.hl7.fhir.utilities.Utilities; -import org.hl7.fhir.utilities.cache.NpmPackage; +import org.hl7.fhir.utilities.npm.NpmPackage; import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType; import org.hl7.fhir.utilities.validation.ValidationMessage.Source; diff --git a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/context/SimpleWorkerContext.java b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/context/SimpleWorkerContext.java index 78718cce6..72a0f050c 100644 --- a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/context/SimpleWorkerContext.java +++ b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/context/SimpleWorkerContext.java @@ -79,7 +79,7 @@ import org.hl7.fhir.r4.utils.IResourceValidator; import org.hl7.fhir.r4.utils.NarrativeGenerator; import org.hl7.fhir.utilities.CSFileInputStream; import org.hl7.fhir.utilities.Utilities; -import org.hl7.fhir.utilities.cache.NpmPackage; +import org.hl7.fhir.utilities.npm.NpmPackage; import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType; import org.hl7.fhir.utilities.validation.ValidationMessage.Source; diff --git a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/model/BaseDateTimeType.java b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/model/BaseDateTimeType.java index 04c9a3429..699db4c0e 100644 --- a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/model/BaseDateTimeType.java +++ b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/model/BaseDateTimeType.java @@ -939,4 +939,9 @@ public abstract class BaseDateTimeType extends PrimitiveType { } + @Override + public String fpValue() { + return "@"+primitiveValue(); + } + } \ No newline at end of file diff --git a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/model/CodeSystem.java b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/model/CodeSystem.java index 946f80d2e..43a1b69ea 100644 --- a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/model/CodeSystem.java +++ b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/model/CodeSystem.java @@ -37,6 +37,7 @@ package org.hl7.fhir.r4.model; import java.util.*; import org.hl7.fhir.utilities.Utilities; +import org.hl7.fhir.r4.model.CodeSystem.ConceptDefinitionComponentSorter; import org.hl7.fhir.r4.model.Enumerations.*; import ca.uhn.fhir.model.api.annotation.ResourceDef; import ca.uhn.fhir.model.api.annotation.SearchParamDefinition; @@ -5049,6 +5050,30 @@ public class CodeSystem extends MetadataResource { return null; } + public class ConceptDefinitionComponentSorter implements Comparator { + @Override + public int compare(ConceptDefinitionComponent l, ConceptDefinitionComponent r) { + return l.getCode().compareTo(r.getCode()); + } + } + + public void sort() { + sort(getConcept(), new ConceptDefinitionComponentSorter()); + } + + public void sort(List list, Comparator comp) { + Collections.sort(list, comp); + for (ConceptDefinitionComponent def : list) { + if (def.hasConcept()) { + sort (def.getConcept(), comp); + } + } + } + + public void sort(Comparator comp) { + sort(getConcept(), comp); + } + // end addition } \ No newline at end of file diff --git a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/model/ExpressionNode.java b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/model/ExpressionNode.java index a061937a9..3ed27a087 100644 --- a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/model/ExpressionNode.java +++ b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/model/ExpressionNode.java @@ -34,6 +34,7 @@ package org.hl7.fhir.r4.model; import java.util.ArrayList; import java.util.List; +import org.hl7.fhir.utilities.SourceLocation; import org.hl7.fhir.utilities.Utilities; public class ExpressionNode { @@ -41,31 +42,6 @@ public class ExpressionNode { public enum Kind { Name, Function, Constant, Group, Unary } - public static class SourceLocation { - private int line; - private int column; - public SourceLocation(int line, int column) { - super(); - this.line = line; - this.column = column; - } - public int getLine() { - return line; - } - public int getColumn() { - return column; - } - public void setLine(int line) { - this.line = line; - } - public void setColumn(int column) { - this.column = column; - } - - public String toString() { - return Integer.toString(line)+", "+Integer.toString(column); - } - } public enum Function { Custom, diff --git a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/model/PrimitiveType.java b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/model/PrimitiveType.java index 30df38036..4b8a95ca8 100644 --- a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/model/PrimitiveType.java +++ b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/model/PrimitiveType.java @@ -249,4 +249,7 @@ public abstract class PrimitiveType extends Type implements IPrimitiveType return StringUtils.isNotBlank(getValueAsString()); } + public String fpValue() { + return primitiveValue(); + } } \ No newline at end of file diff --git a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/terminologies/CodeSystemUtilities.java b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/terminologies/CodeSystemUtilities.java index da74a6e0f..f4b21442b 100644 --- a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/terminologies/CodeSystemUtilities.java +++ b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/terminologies/CodeSystemUtilities.java @@ -67,7 +67,7 @@ public class CodeSystemUtilities { public static void setNotSelectable(CodeSystem cs, ConceptDefinitionComponent concept) throws FHIRFormatError { defineNotSelectableProperty(cs); - ConceptPropertyComponent p = getProperty(concept, "notSelectable"); + ConceptPropertyComponent p = getProperty(concept, "abstract"); if (p != null) p.setValue(new BooleanType(true)); else diff --git a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/test/utils/TestingUtilities.java b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/test/utils/TestingUtilities.java index 019e639df..5fb2074a6 100644 --- a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/test/utils/TestingUtilities.java +++ b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/test/utils/TestingUtilities.java @@ -50,8 +50,8 @@ import org.hl7.fhir.r4.model.Parameters; import org.hl7.fhir.utilities.CSFile; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; -import org.hl7.fhir.utilities.cache.FilesystemPackageCacheManager; -import org.hl7.fhir.utilities.cache.ToolsVersion; +import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; +import org.hl7.fhir.utilities.npm.ToolsVersion; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; diff --git a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/FHIRLexer.java b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/FHIRLexer.java index 38df5e9a4..83619c66b 100644 --- a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/FHIRLexer.java +++ b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/FHIRLexer.java @@ -34,7 +34,7 @@ import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.r4.model.ExpressionNode; -import org.hl7.fhir.r4.model.ExpressionNode.SourceLocation; +import org.hl7.fhir.utilities.SourceLocation; import org.hl7.fhir.utilities.Utilities; // shared lexer for concrete syntaxes diff --git a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/FHIRPathEngine.java b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/FHIRPathEngine.java index aedd55871..7bc7ec1c0 100644 --- a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/FHIRPathEngine.java +++ b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/FHIRPathEngine.java @@ -19,6 +19,7 @@ import org.hl7.fhir.r4.model.StructureDefinition.TypeDerivationRule; import org.hl7.fhir.r4.model.TypeDetails.ProfiledType; import org.hl7.fhir.r4.utils.FHIRLexer.FHIRLexerException; import org.hl7.fhir.r4.utils.FHIRPathEngine.IEvaluationContext.FunctionDetails; +import org.hl7.fhir.utilities.SourceLocation; import org.hl7.fhir.utilities.TerminologyServiceOptions; import org.hl7.fhir.utilities.Utilities; @@ -414,10 +415,10 @@ public class FHIRPathEngine { } StructureDefinition sd = worker.fetchResource(StructureDefinition.class, ctxt); if (sd == null) - throw new PathEngineException("Unknown context "+context); - ElementDefinitionMatch ed = getElementDefinition(sd, context, true); + throw new PathEngineException("Unknown context "+context, expr.getStart(), expr.toString()); + ElementDefinitionMatch ed = getElementDefinition(sd, context, true, expr); if (ed == null) - throw new PathEngineException("Unknown context element "+context); + throw new PathEngineException("Unknown context element "+context, expr.getStart(), expr.toString()); if (ed.fixedType != null) types = new TypeDetails(CollectionStatus.SINGLETON, ed.fixedType); else if (ed.getDefinition().getType().isEmpty() || isAbstractType(ed.getDefinition().getType())) @@ -438,9 +439,9 @@ public class FHIRPathEngine { if (!context.contains(".")) { types = new TypeDetails(CollectionStatus.SINGLETON, sd.getUrl()); } else { - ElementDefinitionMatch ed = getElementDefinition(sd, context, true); + ElementDefinitionMatch ed = getElementDefinition(sd, context, true, expr); if (ed == null) - throw new PathEngineException("Unknown context element "+context); + throw new PathEngineException("Unknown context element "+context, expr.getStart(), expr.toString()); if (ed.fixedType != null) types = new TypeDetails(CollectionStatus.SINGLETON, ed.fixedType); else if (ed.getDefinition().getType().isEmpty() || isAbstractType(ed.getDefinition().getType())) @@ -1161,7 +1162,7 @@ public class FHIRPathEngine { work.addAll(work2); break; case Constant: - Base b = resolveConstant(context, exp.getConstant(), false); + Base b = resolveConstant(context, exp.getConstant(), false, exp); if (b != null) work.add(b); break; @@ -1177,15 +1178,15 @@ public class FHIRPathEngine { ExpressionNode next = exp.getOpNext(); ExpressionNode last = exp; while (next != null) { - List work2 = preOperate(work, last.getOperation()); + List work2 = preOperate(work, last.getOperation(), exp); if (work2 != null) work = work2; else if (last.getOperation() == Operation.Is || last.getOperation() == Operation.As) { work2 = executeTypeName(context, focus, next, false); - work = operate(context, work, last.getOperation(), work2); + work = operate(context, work, last.getOperation(), work2, last); } else { work2 = execute(context, focus, next, true); - work = operate(context, work, last.getOperation(), work2); + work = operate(context, work, last.getOperation(), work2, last); // System.out.println("Result of {'"+last.toString()+" "+last.getOperation().toCode()+" "+next.toString()+"'}: "+focus.toString()); } last = next; @@ -1206,7 +1207,7 @@ public class FHIRPathEngine { } - private List preOperate(List left, Operation operation) throws PathEngineException { + private List preOperate(List left, Operation operation, ExpressionNode expr) throws PathEngineException { if (left.size() == 0) return null; switch (operation) { @@ -1215,7 +1216,7 @@ public class FHIRPathEngine { case Or: return isBoolean(left, true) ? makeBoolean(true) : null; case Implies: - Equality v = asBool(left); + Equality v = asBool(left, expr); return v == Equality.False ? makeBoolean(true) : null; default: return null; @@ -1246,13 +1247,13 @@ public class FHIRPathEngine { else if (atEntry && exp.getName().equals("$total")) result.update(anything(CollectionStatus.UNORDERED)); else if (atEntry && focus == null) - result.update(executeContextType(context, exp.getName())); + result.update(executeContextType(context, exp.getName(), exp)); else { for (String s : focus.getTypes()) { result.update(executeType(s, exp, atEntry)); } if (result.hasNoTypes()) - throw new PathEngineException("The name "+exp.getName()+" is not valid for any of the possible types: "+focus.describe()); + throw new PathEngineException("The name "+exp.getName()+" is not valid for any of the possible types: "+focus.describe(), exp.getStart(), exp.toString()); } break; case Function: @@ -1262,7 +1263,7 @@ public class FHIRPathEngine { result.addType("integer"); break; case Constant: - result.update(resolveConstantType(context, exp.getConstant())); + result.update(resolveConstantType(context, exp.getConstant(), exp)); break; case Group: result.update(executeType(context, focus, exp.getGroup(), atEntry)); @@ -1282,7 +1283,7 @@ public class FHIRPathEngine { work = executeTypeName(context, focus, next, atEntry); else work = executeType(context, focus, next, atEntry); - result = operateTypes(result, last.getOperation(), work); + result = operateTypes(result, last.getOperation(), work, exp); last = next; next = next.getOpNext(); } @@ -1291,16 +1292,16 @@ public class FHIRPathEngine { return result; } - private Base resolveConstant(ExecutionContext context, Base constant, boolean beforeContext) throws PathEngineException { + private Base resolveConstant(ExecutionContext context, Base constant, boolean beforeContext, ExpressionNode expr) throws PathEngineException { if (!(constant instanceof FHIRConstant)) return constant; FHIRConstant c = (FHIRConstant) constant; if (c.getValue().startsWith("%")) { - return resolveConstant(context, c.getValue(), beforeContext); + return resolveConstant(context, c.getValue(), beforeContext, expr); } else if (c.getValue().startsWith("@")) { return processDateConstant(context.appInfo, c.getValue().substring(1)); } else - throw new PathEngineException("Invaild FHIR Constant "+c.getValue()); + throw new PathEngineException("Invaild FHIR Constant "+c.getValue(), expr.getStart(), expr.toString()); } private Base processDateConstant(Object appInfo, String value) throws PathEngineException { @@ -1322,7 +1323,7 @@ public class FHIRPathEngine { } - private Base resolveConstant(ExecutionContext context, String s, boolean beforeContext) throws PathEngineException { + private Base resolveConstant(ExecutionContext context, String s, boolean beforeContext, ExpressionNode expr) throws PathEngineException { if (s.equals("%sct")) return new StringType("http://snomed.info/sct").noExtensions(); else if (s.equals("%loinc")) @@ -1331,11 +1332,11 @@ public class FHIRPathEngine { return new StringType("http://unitsofmeasure.org").noExtensions(); else if (s.equals("%resource")) { if (context.focusResource == null) - throw new PathEngineException("Cannot use %resource in this context"); + throw new PathEngineException("Cannot use %resource in this context", expr.getStart(), expr.toString()); return context.focusResource; } else if (s.equals("%rootResource")) { if (context.rootResource == null) - throw new PathEngineException("Cannot use %rootResource in this context"); + throw new PathEngineException("Cannot use %rootResource in this context", expr.getStart(), expr.toString()); return context.rootResource; } else if (s.equals("%context")) { return context.context; @@ -1348,7 +1349,7 @@ public class FHIRPathEngine { else if (s.startsWith("%`ext-")) return new StringType("http://hl7.org/fhir/StructureDefinition/"+s.substring(6, s.length()-1)).noExtensions(); else if (hostServices == null) - throw new PathEngineException("Unknown fixed constant '"+s+"'"); + throw new PathEngineException("Unknown fixed constant '"+s+"'", expr.getStart(), expr.toString()); else return hostServices.resolveConstant(context.appInfo, s.substring(1), beforeContext); } @@ -1408,39 +1409,39 @@ public class FHIRPathEngine { } - private List operate(ExecutionContext context, List left, Operation operation, List right) throws FHIRException { + private List operate(ExecutionContext context, List left, Operation operation, List right, ExpressionNode expr) throws FHIRException { switch (operation) { case Equals: return opEquals(left, right); - case Equivalent: return opEquivalent(left, right); - case NotEquals: return opNotEquals(left, right); - case NotEquivalent: return opNotEquivalent(left, right); - case LessThan: return opLessThan(left, right); - case Greater: return opGreater(left, right); - case LessOrEqual: return opLessOrEqual(left, right); - case GreaterOrEqual: return opGreaterOrEqual(left, right); - case Union: return opUnion(left, right); - case In: return opIn(left, right); - case MemberOf: return opMemberOf(context, left, right); - case Contains: return opContains(left, right); - case Or: return opOr(left, right); - case And: return opAnd(left, right); - case Xor: return opXor(left, right); - case Implies: return opImplies(left, right); - case Plus: return opPlus(left, right); - case Times: return opTimes(left, right); - case Minus: return opMinus(left, right); - case Concatenate: return opConcatenate(left, right); - case DivideBy: return opDivideBy(left, right); - case Div: return opDiv(left, right); - case Mod: return opMod(left, right); - case Is: return opIs(left, right); - case As: return opAs(left, right); + case Equivalent: return opEquivalent(left, right, expr); + case NotEquals: return opNotEquals(left, right, expr); + case NotEquivalent: return opNotEquivalent(left, right, expr); + case LessThan: return opLessThan(left, right, expr); + case Greater: return opGreater(left, right, expr); + case LessOrEqual: return opLessOrEqual(left, right, expr); + case GreaterOrEqual: return opGreaterOrEqual(left, right, expr); + case Union: return opUnion(left, right, expr); + case In: return opIn(left, right, expr); + case MemberOf: return opMemberOf(context, left, right, expr); + case Contains: return opContains(left, right, expr); + case Or: return opOr(left, right, expr); + case And: return opAnd(left, right, expr); + case Xor: return opXor(left, right, expr); + case Implies: return opImplies(left, right, expr); + case Plus: return opPlus(left, right, expr); + case Times: return opTimes(left, right, expr); + case Minus: return opMinus(left, right, expr); + case Concatenate: return opConcatenate(left, right, expr); + case DivideBy: return opDivideBy(left, right, expr); + case Div: return opDiv(left, right, expr); + case Mod: return opMod(left, right, expr); + case Is: return opIs(left, right, expr); + case As: return opAs(left, right, expr); default: throw new Error("Not Done Yet: "+operation.toCode()); } } - private List opAs(List left, List right) { + private List opAs(List left, List right, ExpressionNode expr) { List result = new ArrayList<>(); if (right.size() != 1) return result; @@ -1455,7 +1456,7 @@ public class FHIRPathEngine { } - private List opIs(List left, List right) { + private List opIs(List left, List right, ExpressionNode expr) { List result = new ArrayList(); if (left.size() != 1 || right.size() != 1) result.add(new BooleanType(false).noExtensions()); @@ -1472,7 +1473,7 @@ public class FHIRPathEngine { } - private TypeDetails operateTypes(TypeDetails left, Operation operation, TypeDetails right) { + private TypeDetails operateTypes(TypeDetails left, Operation operation, TypeDetails right, ExpressionNode expr) { switch (operation) { case Equals: return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); case Equivalent: return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); @@ -1514,6 +1515,13 @@ public class FHIRPathEngine { result.addType(TypeDetails.FP_Decimal); else if (left.hasType(worker, "string", "id", "code", "uri") && right.hasType(worker, "string", "id", "code", "uri")) result.addType(TypeDetails.FP_String); + else if (left.hasType(worker, "date", "dateTime", "instant")) { + if (right.hasType(worker, "Quantity")) { + result.addType(left.getType()); + } else { + throw new PathEngineException(String.format("Error in date arithmetic: Unable to add type {0} to {1}", right.getType(), left.getType()), expr.getStart(), expr.toString()); + } + } return result; case Minus: result = new TypeDetails(CollectionStatus.SINGLETON); @@ -1521,6 +1529,13 @@ public class FHIRPathEngine { result.addType(TypeDetails.FP_Integer); else if (left.hasType(worker, "integer", "decimal") && right.hasType(worker, "integer", "decimal")) result.addType(TypeDetails.FP_Decimal); + else if (left.hasType(worker, "date", "dateTime", "instant")) { + if (right.hasType(worker, "Quantity")) { + result.addType(left.getType()); + } else { + throw new PathEngineException(String.format("Error in date arithmetic: Unable to subtract type {0} from {1}", right.getType(), left.getType())); + } + } return result; case Div: case Mod: @@ -1565,7 +1580,7 @@ public class FHIRPathEngine { return makeBoolean(res); } - private List opNotEquals(List left, List right) { + private List opNotEquals(List left, List right, ExpressionNode expr) { if (!legacyMode && (left.size() == 0 || right.size() == 0)) return new ArrayList(); @@ -1634,9 +1649,9 @@ public class FHIRPathEngine { } - private boolean doEquivalent(Base left, Base right) throws PathEngineException { + private boolean doEquivalent(Base left, Base right, ExpressionNode expr) throws PathEngineException { if (left instanceof Quantity && right instanceof Quantity) - return qtyEquivalent((Quantity) left, (Quantity) right); + return qtyEquivalent((Quantity) left, (Quantity) right, expr); if (left.hasType("integer") && right.hasType("integer")) return doEquals(left, right); if (left.hasType("boolean") && right.hasType("boolean")) @@ -1648,7 +1663,7 @@ public class FHIRPathEngine { if (left.hasType(FHIR_TYPES_STRING) && right.hasType(FHIR_TYPES_STRING)) return Utilities.equivalent(convertToString(left), convertToString(right)); - throw new PathEngineException(String.format("Unable to determine equivalence between %s and %s", left.fhirType(), right.fhirType())); + throw new PathEngineException(String.format("Unable to determine equivalence between %s and %s", left.fhirType(), right.fhirType()), expr.getStart(), expr.toString()); } private boolean qtyEqual(Quantity left, Quantity right) { @@ -1689,19 +1704,19 @@ public class FHIRPathEngine { } - private boolean qtyEquivalent(Quantity left, Quantity right) throws PathEngineException { + private boolean qtyEquivalent(Quantity left, Quantity right, ExpressionNode expr) throws PathEngineException { if (worker.getUcumService() != null) { DecimalType dl = qtyToCanonical(left); DecimalType dr = qtyToCanonical(right); if (dl != null && dr != null) - return doEquivalent(dl, dr); + return doEquivalent(dl, dr, expr); } return left.equals(right); } - private List opEquivalent(List left, List right) throws PathEngineException { + private List opEquivalent(List left, List right, ExpressionNode expr) throws PathEngineException { if (left.size() != right.size()) return makeBoolean(false); @@ -1709,7 +1724,7 @@ public class FHIRPathEngine { for (int i = 0; i < left.size(); i++) { boolean found = false; for (int j = 0; j < right.size(); j++) { - if (doEquivalent(left.get(i), right.get(j))) { + if (doEquivalent(left.get(i), right.get(j), expr)) { found = true; break; } @@ -1722,7 +1737,7 @@ public class FHIRPathEngine { return makeBoolean(res); } - private List opNotEquivalent(List left, List right) throws PathEngineException { + private List opNotEquivalent(List left, List right, ExpressionNode expr) throws PathEngineException { if (left.size() != right.size()) return makeBoolean(true); @@ -1730,7 +1745,7 @@ public class FHIRPathEngine { for (int i = 0; i < left.size(); i++) { boolean found = false; for (int j = 0; j < right.size(); j++) { - if (doEquivalent(left.get(i), right.get(j))) { + if (doEquivalent(left.get(i), right.get(j), expr)) { found = true; break; } @@ -1745,7 +1760,7 @@ public class FHIRPathEngine { private final static String[] FHIR_TYPES_STRING = new String[] {"string", "uri", "code", "oid", "id", "uuid", "sid", "markdown", "base64Binary", "canonical", "url"}; - private List opLessThan(List left, List right) throws FHIRException { + private List opLessThan(List left, List right, ExpressionNode expr) throws FHIRException { if (left.size() == 0 || right.size() == 0) return new ArrayList(); @@ -1761,12 +1776,12 @@ public class FHIRPathEngine { else if ((l.hasType("time")) && (r.hasType("time"))) return makeBoolean(l.primitiveValue().compareTo(r.primitiveValue()) < 0); else - throw new PathEngineException("Unable to compare values of type "+l.fhirType()+" and "+r.fhirType()); + throw new PathEngineException("Unable to compare values of type "+l.fhirType()+" and "+r.fhirType(), expr.getStart(), expr.toString()); } else if (left.size() == 1 && right.size() == 1 && left.get(0).fhirType().equals("Quantity") && right.get(0).fhirType().equals("Quantity") ) { List lUnit = left.get(0).listChildrenByName("code"); List rUnit = right.get(0).listChildrenByName("code"); if (Base.compareDeep(lUnit, rUnit, true)) { - return opLessThan(left.get(0).listChildrenByName("value"), right.get(0).listChildrenByName("value")); + return opLessThan(left.get(0).listChildrenByName("value"), right.get(0).listChildrenByName("value"), expr); } else { if (worker.getUcumService() == null) return makeBoolean(false); @@ -1775,14 +1790,14 @@ public class FHIRPathEngine { dl.add(qtyToCanonical((Quantity) left.get(0))); List dr = new ArrayList(); dr.add(qtyToCanonical((Quantity) right.get(0))); - return opLessThan(dl, dr); + return opLessThan(dl, dr, expr); } } } return new ArrayList(); } - private List opGreater(List left, List right) throws FHIRException { + private List opGreater(List left, List right, ExpressionNode expr) throws FHIRException { if (left.size() == 0 || right.size() == 0) return new ArrayList(); if (left.size() == 1 && right.size() == 1 && left.get(0).isPrimitive() && right.get(0).isPrimitive()) { @@ -1797,12 +1812,12 @@ public class FHIRPathEngine { else if ((l.hasType("time")) && (r.hasType("time"))) return makeBoolean(l.primitiveValue().compareTo(r.primitiveValue()) > 0); else - throw new PathEngineException("Unable to compare values of type "+l.fhirType()+" and "+r.fhirType()); + throw new PathEngineException("Unable to compare values of type "+l.fhirType()+" and "+r.fhirType(), expr.getStart(), expr.toString()); } else if (left.size() == 1 && right.size() == 1 && left.get(0).fhirType().equals("Quantity") && right.get(0).fhirType().equals("Quantity") ) { List lUnit = left.get(0).listChildrenByName("unit"); List rUnit = right.get(0).listChildrenByName("unit"); if (Base.compareDeep(lUnit, rUnit, true)) { - return opGreater(left.get(0).listChildrenByName("value"), right.get(0).listChildrenByName("value")); + return opGreater(left.get(0).listChildrenByName("value"), right.get(0).listChildrenByName("value"), expr); } else { if (worker.getUcumService() == null) return makeBoolean(false); @@ -1811,14 +1826,14 @@ public class FHIRPathEngine { dl.add(qtyToCanonical((Quantity) left.get(0))); List dr = new ArrayList(); dr.add(qtyToCanonical((Quantity) right.get(0))); - return opGreater(dl, dr); + return opGreater(dl, dr, expr); } } } return new ArrayList(); } - private List opLessOrEqual(List left, List right) throws FHIRException { + private List opLessOrEqual(List left, List right, ExpressionNode expr) throws FHIRException { if (left.size() == 0 || right.size() == 0) return new ArrayList(); if (left.size() == 1 && right.size() == 1 && left.get(0).isPrimitive() && right.get(0).isPrimitive()) { @@ -1833,14 +1848,14 @@ public class FHIRPathEngine { else if ((l.hasType("time")) && (r.hasType("time"))) return makeBoolean(l.primitiveValue().compareTo(r.primitiveValue()) <= 0); else - throw new PathEngineException("Unable to compare values of type "+l.fhirType()+" and "+r.fhirType()); + throw new PathEngineException("Unable to compare values of type "+l.fhirType()+" and "+r.fhirType(), expr.getStart(), expr.toString()); } else if (left.size() == 1 && right.size() == 1 && left.get(0).fhirType().equals("Quantity") && right.get(0).fhirType().equals("Quantity") ) { List lUnits = left.get(0).listChildrenByName("unit"); String lunit = lUnits.size() == 1 ? lUnits.get(0).primitiveValue() : null; List rUnits = right.get(0).listChildrenByName("unit"); String runit = rUnits.size() == 1 ? rUnits.get(0).primitiveValue() : null; if ((lunit == null && runit == null) || lunit.equals(runit)) { - return opLessOrEqual(left.get(0).listChildrenByName("value"), right.get(0).listChildrenByName("value")); + return opLessOrEqual(left.get(0).listChildrenByName("value"), right.get(0).listChildrenByName("value"), expr); } else { if (worker.getUcumService() == null) return makeBoolean(false); @@ -1849,14 +1864,14 @@ public class FHIRPathEngine { dl.add(qtyToCanonical((Quantity) left.get(0))); List dr = new ArrayList(); dr.add(qtyToCanonical((Quantity) right.get(0))); - return opLessOrEqual(dl, dr); + return opLessOrEqual(dl, dr, expr); } } } return new ArrayList(); } - private List opGreaterOrEqual(List left, List right) throws FHIRException { + private List opGreaterOrEqual(List left, List right, ExpressionNode expr) throws FHIRException { if (left.size() == 0 || right.size() == 0) return new ArrayList(); if (left.size() == 1 && right.size() == 1 && left.get(0).isPrimitive() && right.get(0).isPrimitive()) { @@ -1871,12 +1886,12 @@ public class FHIRPathEngine { else if ((l.hasType("time")) && (r.hasType("time"))) return makeBoolean(l.primitiveValue().compareTo(r.primitiveValue()) >= 0); else - throw new PathEngineException("Unable to compare values of type "+l.fhirType()+" and "+r.fhirType()); + throw new PathEngineException("Unable to compare values of type "+l.fhirType()+" and "+r.fhirType(), expr.getStart(), expr.toString()); } else if (left.size() == 1 && right.size() == 1 && left.get(0).fhirType().equals("Quantity") && right.get(0).fhirType().equals("Quantity") ) { List lUnit = left.get(0).listChildrenByName("unit"); List rUnit = right.get(0).listChildrenByName("unit"); if (Base.compareDeep(lUnit, rUnit, true)) { - return opGreaterOrEqual(left.get(0).listChildrenByName("value"), right.get(0).listChildrenByName("value")); + return opGreaterOrEqual(left.get(0).listChildrenByName("value"), right.get(0).listChildrenByName("value"), expr); } else { if (worker.getUcumService() == null) return makeBoolean(false); @@ -1885,14 +1900,14 @@ public class FHIRPathEngine { dl.add(qtyToCanonical((Quantity) left.get(0))); List dr = new ArrayList(); dr.add(qtyToCanonical((Quantity) right.get(0))); - return opGreaterOrEqual(dl, dr); + return opGreaterOrEqual(dl, dr, expr); } } } return new ArrayList(); } - private List opMemberOf(ExecutionContext context, List left, List right) throws FHIRException { + private List opMemberOf(ExecutionContext context, List left, List right, ExpressionNode expr) throws FHIRException { boolean ans = false; ValueSet vs = hostServices != null ? hostServices.resolveValueSet(context.appInfo, right.get(0).primitiveValue()) : worker.fetchResource(ValueSet.class, right.get(0).primitiveValue()); if (vs != null) { @@ -1912,7 +1927,7 @@ public class FHIRPathEngine { return makeBoolean(ans); } - private List opIn(List left, List right) throws FHIRException { + private List opIn(List left, List right, ExpressionNode expr) throws FHIRException { if (left.size() == 0) return new ArrayList(); if (right.size() == 0) @@ -1935,7 +1950,7 @@ public class FHIRPathEngine { return makeBoolean(ans); } - private List opContains(List left, List right) { + private List opContains(List left, List right, ExpressionNode expr) { if (left.size() == 0 || right.size() == 0) return new ArrayList(); boolean ans = true; @@ -1956,17 +1971,17 @@ public class FHIRPathEngine { return makeBoolean(ans); } - private List opPlus(List left, List right) throws PathEngineException { + private List opPlus(List left, List right, ExpressionNode expr) throws PathEngineException { if (left.size() == 0 || right.size() == 0) return new ArrayList(); if (left.size() > 1) - throw new PathEngineException("Error performing +: left operand has more than one value"); + throw new PathEngineException("Error performing +: left operand has more than one value", expr.getStart(), expr.toString()); if (!left.get(0).isPrimitive()) - throw new PathEngineException(String.format("Error performing +: left operand has the wrong type (%s)", left.get(0).fhirType())); + throw new PathEngineException(String.format("Error performing +: left operand has the wrong type (%s)", left.get(0).fhirType()), expr.getStart(), expr.toString()); if (right.size() > 1) - throw new PathEngineException("Error performing +: right operand has more than one value"); - if (!right.get(0).isPrimitive()) - throw new PathEngineException(String.format("Error performing +: right operand has the wrong type (%s)", right.get(0).fhirType())); + throw new PathEngineException("Error performing +: right operand has more than one value", expr.getStart(), expr.toString()); + if (!right.get(0).isPrimitive() && !((left.get(0).isDateTime() || "0".equals(left.get(0).primitiveValue()) || left.get(0).hasType("Quantity")) && right.get(0).hasType("Quantity"))) + throw new PathEngineException(String.format("Error performing +: right operand has the wrong type (%s)", right.get(0).fhirType()), expr.getStart(), expr.toString()); List result = new ArrayList(); Base l = left.get(0); @@ -1977,22 +1992,78 @@ public class FHIRPathEngine { result.add(new IntegerType(Integer.parseInt(l.primitiveValue()) + Integer.parseInt(r.primitiveValue()))); else if (l.hasType("decimal", "integer") && r.hasType("decimal", "integer")) result.add(new DecimalType(new BigDecimal(l.primitiveValue()).add(new BigDecimal(r.primitiveValue())))); + else if (l.isDateTime() && r.hasType("Quantity")) + result.add(dateAdd((BaseDateTimeType) l, (Quantity) r, false, expr)); else - throw new PathEngineException(String.format("Error performing +: left and right operand have incompatible or illegal types (%s, %s)", left.get(0).fhirType(), right.get(0).fhirType())); + throw new PathEngineException(String.format("Error performing +: left and right operand have incompatible or illegal types (%s, %s)", left.get(0).fhirType(), right.get(0).fhirType()), expr.getStart(), expr.toString()); return result; } - private List opTimes(List left, List right) throws PathEngineException { + private BaseDateTimeType dateAdd(BaseDateTimeType d, Quantity q, boolean negate, ExpressionNode expr) { + BaseDateTimeType result = (BaseDateTimeType) d.copy(); + + int value = negate ? 0 - q.getValue().intValue() : q.getValue().intValue(); + switch (q.hasCode() ? q.getCode() : q.getUnit()) { + case "years": + case "year": + result.add(Calendar.YEAR, value); + break; + case "a": + throw new PathEngineException(String.format("Error in date arithmetic: attempt to add a definite quantity duration time unit %s", q.getCode()), expr.getStart(), expr.toString()); + case "months": + case "month": + result.add(Calendar.MONTH, value); + break; + case "mo": + throw new PathEngineException(String.format("Error in date arithmetic: attempt to add a definite quantity duration time unit %s", q.getCode()), expr.getStart(), expr.toString()); + case "weeks": + case "week": + case "wk": + result.add(Calendar.DAY_OF_MONTH, value * 7); + break; + case "days": + case "day": + case "d": + result.add(Calendar.DAY_OF_MONTH, value); + break; + case "hours": + case "hour": + case "h": + result.add(Calendar.HOUR, value); + break; + case "minutes": + case "minute": + case "min": + result.add(Calendar.MINUTE, value); + break; + case "seconds": + case "second": + case "s": + result.add(Calendar.SECOND, value); + break; + case "milliseconds": + case "millisecond": + case "ms": + result.add(Calendar.MILLISECOND, value); + break; + default: + throw new PathEngineException(String.format("Error in date arithmetic: unrecognized time unit %s", q.getCode()), expr.getStart(), expr.toString()); + } + return result; + } + + + private List opTimes(List left, List right, ExpressionNode expr) throws PathEngineException { if (left.size() == 0 || right.size() == 0) return new ArrayList(); if (left.size() > 1) - throw new PathEngineException("Error performing *: left operand has more than one value"); + throw new PathEngineException("Error performing *: left operand has more than one value", expr.getStart(), expr.toString()); if (!left.get(0).isPrimitive() && !(left.get(0) instanceof Quantity)) - throw new PathEngineException(String.format("Error performing +: left operand has the wrong type (%s)", left.get(0).fhirType())); + throw new PathEngineException(String.format("Error performing +: left operand has the wrong type (%s)", left.get(0).fhirType()), expr.getStart(), expr.toString()); if (right.size() > 1) - throw new PathEngineException("Error performing *: right operand has more than one value"); + throw new PathEngineException("Error performing *: right operand has more than one value", expr.getStart(), expr.toString()); if (!right.get(0).isPrimitive() && !(right.get(0) instanceof Quantity)) - throw new PathEngineException(String.format("Error performing *: right operand has the wrong type (%s)", right.get(0).fhirType())); + throw new PathEngineException(String.format("Error performing *: right operand has the wrong type (%s)", right.get(0).fhirType()), expr.getStart(), expr.toString()); List result = new ArrayList(); Base l = left.get(0); @@ -2010,23 +2081,23 @@ public class FHIRPathEngine { p = worker.getUcumService().multiply(pl, pr); result.add(pairToQty(p)); } catch (UcumException e) { - throw new PathEngineException(e.getMessage(), e); + throw new PathEngineException(e.getMessage(), expr.getOpStart(), expr.toString(), e); } } else - throw new PathEngineException(String.format("Error performing *: left and right operand have incompatible or illegal types (%s, %s)", left.get(0).fhirType(), right.get(0).fhirType())); + throw new PathEngineException(String.format("Error performing *: left and right operand have incompatible or illegal types (%s, %s)", left.get(0).fhirType(), right.get(0).fhirType()), expr.getStart(), expr.toString()); return result; } - private List opConcatenate(List left, List right) throws PathEngineException { + private List opConcatenate(List left, List right, ExpressionNode expr) throws PathEngineException { if (left.size() > 1) - throw new PathEngineException("Error performing &: left operand has more than one value"); + throw new PathEngineException("Error performing &: left operand has more than one value", expr.getStart(), expr.toString()); if (left.size() > 0 && !left.get(0).hasType(FHIR_TYPES_STRING)) - throw new PathEngineException(String.format("Error performing &: left operand has the wrong type (%s)", left.get(0).fhirType())); + throw new PathEngineException(String.format("Error performing &: left operand has the wrong type (%s)", left.get(0).fhirType()), expr.getStart(), expr.toString()); if (right.size() > 1) - throw new PathEngineException("Error performing &: right operand has more than one value"); + throw new PathEngineException("Error performing &: right operand has more than one value", expr.getStart(), expr.toString()); if (right.size() > 0 && !right.get(0).hasType(FHIR_TYPES_STRING)) - throw new PathEngineException(String.format("Error performing &: right operand has the wrong type (%s)", right.get(0).fhirType())); + throw new PathEngineException(String.format("Error performing &: right operand has the wrong type (%s)", right.get(0).fhirType()), expr.getStart(), expr.toString()); List result = new ArrayList(); String l = left.size() == 0 ? "" : left.get(0).primitiveValue(); @@ -2035,7 +2106,7 @@ public class FHIRPathEngine { return result; } - private List opUnion(List left, List right) { + private List opUnion(List left, List right, ExpressionNode expr) { List result = new ArrayList(); for (Base item : left) { if (!doContains(result, item)) @@ -2058,9 +2129,9 @@ public class FHIRPathEngine { } - private List opAnd(List left, List right) throws PathEngineException { - Equality l = asBool(left); - Equality r = asBool(right); + private List opAnd(List left, List right, ExpressionNode expr) throws PathEngineException { + Equality l = asBool(left, expr); + Equality r = asBool(right, expr); switch (l) { case False: return makeBoolean(false); case Null: @@ -2082,9 +2153,9 @@ public class FHIRPathEngine { return list.size() == 1 && list.get(0) instanceof BooleanType && ((BooleanType) list.get(0)).booleanValue() == b; } - private List opOr(List left, List right) throws PathEngineException { - Equality l = asBool(left); - Equality r = asBool(right); + private List opOr(List left, List right, ExpressionNode expr) throws PathEngineException { + Equality l = asBool(left, expr); + Equality r = asBool(right, expr); switch (l) { case True: return makeBoolean(true); case Null: @@ -2102,9 +2173,9 @@ public class FHIRPathEngine { return makeNull(); } - private List opXor(List left, List right) throws PathEngineException { - Equality l = asBool(left); - Equality r = asBool(right); + private List opXor(List left, List right, ExpressionNode expr) throws PathEngineException { + Equality l = asBool(left, expr); + Equality r = asBool(right, expr); switch (l) { case True: switch (r) { @@ -2124,13 +2195,13 @@ public class FHIRPathEngine { return makeNull(); } - private List opImplies(List left, List right) throws PathEngineException { - Equality eq = asBool(left); + private List opImplies(List left, List right, ExpressionNode expr) throws PathEngineException { + Equality eq = asBool(left, expr); if (eq == Equality.False) return makeBoolean(true); else if (right.size() == 0) return makeNull(); - else switch (asBool(right)) { + else switch (asBool(right, expr)) { case False: return eq == Equality.Null ? makeNull() : makeBoolean(false); case Null: return makeNull(); case True: return makeBoolean(true); @@ -2139,17 +2210,17 @@ public class FHIRPathEngine { } - private List opMinus(List left, List right) throws PathEngineException { + private List opMinus(List left, List right, ExpressionNode expr) throws PathEngineException { if (left.size() == 0 || right.size() == 0) return new ArrayList(); if (left.size() > 1) - throw new PathEngineException("Error performing -: left operand has more than one value"); + throw new PathEngineException("Error performing -: left operand has more than one value", expr.getStart(), expr.toString()); if (!left.get(0).isPrimitive()) - throw new PathEngineException(String.format("Error performing -: left operand has the wrong type (%s)", left.get(0).fhirType())); + throw new PathEngineException(String.format("Error performing -: left operand has the wrong type (%s)", left.get(0).fhirType()), expr.getStart(), expr.toString()); if (right.size() > 1) - throw new PathEngineException("Error performing -: right operand has more than one value"); - if (!right.get(0).isPrimitive()) - throw new PathEngineException(String.format("Error performing -: right operand has the wrong type (%s)", right.get(0).fhirType())); + throw new PathEngineException("Error performing -: right operand has more than one value", expr.getStart(), expr.toString()); + if (!right.get(0).isPrimitive() && !((left.get(0).isDateTime() || "0".equals(left.get(0).primitiveValue()) || left.get(0).hasType("Quantity")) && right.get(0).hasType("Quantity"))) + throw new PathEngineException(String.format("Error performing -: right operand has the wrong type (%s)", right.get(0).fhirType()), expr.getStart(), expr.toString()); List result = new ArrayList(); Base l = left.get(0); @@ -2159,22 +2230,24 @@ public class FHIRPathEngine { result.add(new IntegerType(Integer.parseInt(l.primitiveValue()) - Integer.parseInt(r.primitiveValue()))); else if (l.hasType("decimal", "integer") && r.hasType("decimal", "integer")) result.add(new DecimalType(new BigDecimal(l.primitiveValue()).subtract(new BigDecimal(r.primitiveValue())))); + else if (l.isDateTime() && r.hasType("Quantity")) + result.add(dateAdd((BaseDateTimeType) l, (Quantity) r, true, expr)); else - throw new PathEngineException(String.format("Error performing -: left and right operand have incompatible or illegal types (%s, %s)", left.get(0).fhirType(), right.get(0).fhirType())); + throw new PathEngineException(String.format("Error performing -: left and right operand have incompatible or illegal types (%s, %s)", left.get(0).fhirType(), right.get(0).fhirType()), expr.getStart(), expr.toString()); return result; } - private List opDivideBy(List left, List right) throws PathEngineException { + private List opDivideBy(List left, List right, ExpressionNode expr) throws PathEngineException { if (left.size() == 0 || right.size() == 0) return new ArrayList(); if (left.size() > 1) - throw new PathEngineException("Error performing /: left operand has more than one value"); + throw new PathEngineException("Error performing /: left operand has more than one value", expr.getStart(), expr.toString()); if (!left.get(0).isPrimitive() && !(left.get(0) instanceof Quantity)) - throw new PathEngineException(String.format("Error performing -: left operand has the wrong type (%s)", left.get(0).fhirType())); + throw new PathEngineException(String.format("Error performing -: left operand has the wrong type (%s)", left.get(0).fhirType()), expr.getStart(), expr.toString()); if (right.size() > 1) throw new PathEngineException("Error performing /: right operand has more than one value"); if (!right.get(0).isPrimitive() && !(right.get(0) instanceof Quantity)) - throw new PathEngineException(String.format("Error performing /: right operand has the wrong type (%s)", right.get(0).fhirType())); + throw new PathEngineException(String.format("Error performing /: right operand has the wrong type (%s)", right.get(0).fhirType()), expr.getStart(), expr.toString()); List result = new ArrayList(); Base l = left.get(0); @@ -2197,24 +2270,24 @@ public class FHIRPathEngine { p = worker.getUcumService().multiply(pl, pr); result.add(pairToQty(p)); } catch (UcumException e) { - throw new PathEngineException(e.getMessage(), e); + throw new PathEngineException(e.getMessage(), expr.getOpStart(), expr.toString(), e); } } else - throw new PathEngineException(String.format("Error performing /: left and right operand have incompatible or illegal types (%s, %s)", left.get(0).fhirType(), right.get(0).fhirType())); + throw new PathEngineException(String.format("Error performing /: left and right operand have incompatible or illegal types (%s, %s)", left.get(0).fhirType(), right.get(0).fhirType()), expr.getStart(), expr.toString()); return result; } - private List opDiv(List left, List right) throws PathEngineException { + private List opDiv(List left, List right, ExpressionNode expr) throws PathEngineException { if (left.size() == 0 || right.size() == 0) return new ArrayList(); if (left.size() > 1) - throw new PathEngineException("Error performing div: left operand has more than one value"); + throw new PathEngineException("Error performing div: left operand has more than one value", expr.getStart(), expr.toString()); if (!left.get(0).isPrimitive() && !(left.get(0) instanceof Quantity)) - throw new PathEngineException(String.format("Error performing div: left operand has the wrong type (%s)", left.get(0).fhirType())); + throw new PathEngineException(String.format("Error performing div: left operand has the wrong type (%s)", left.get(0).fhirType()), expr.getStart(), expr.toString()); if (right.size() > 1) - throw new PathEngineException("Error performing div: right operand has more than one value"); + throw new PathEngineException("Error performing div: right operand has more than one value", expr.getStart(), expr.toString()); if (!right.get(0).isPrimitive() && !(right.get(0) instanceof Quantity)) - throw new PathEngineException(String.format("Error performing div: right operand has the wrong type (%s)", right.get(0).fhirType())); + throw new PathEngineException(String.format("Error performing div: right operand has the wrong type (%s)", right.get(0).fhirType()), expr.getStart(), expr.toString()); List result = new ArrayList(); Base l = left.get(0); @@ -2233,21 +2306,21 @@ public class FHIRPathEngine { } } else - throw new PathEngineException(String.format("Error performing div: left and right operand have incompatible or illegal types (%s, %s)", left.get(0).fhirType(), right.get(0).fhirType())); + throw new PathEngineException(String.format("Error performing div: left and right operand have incompatible or illegal types (%s, %s)", left.get(0).fhirType(), right.get(0).fhirType()), expr.getStart(), expr.toString()); return result; } - private List opMod(List left, List right) throws PathEngineException { + private List opMod(List left, List right, ExpressionNode expr) throws PathEngineException { if (left.size() == 0 || right.size() == 0) return new ArrayList(); if (left.size() > 1) - throw new PathEngineException("Error performing mod: left operand has more than one value"); + throw new PathEngineException("Error performing mod: left operand has more than one value", expr.getStart(), expr.toString()); if (!left.get(0).isPrimitive()) - throw new PathEngineException(String.format("Error performing mod: left operand has the wrong type (%s)", left.get(0).fhirType())); + throw new PathEngineException(String.format("Error performing mod: left operand has the wrong type (%s)", left.get(0).fhirType()), expr.getStart(), expr.toString()); if (right.size() > 1) - throw new PathEngineException("Error performing mod: right operand has more than one value"); + throw new PathEngineException("Error performing mod: right operand has more than one value", expr.getStart(), expr.toString()); if (!right.get(0).isPrimitive()) - throw new PathEngineException(String.format("Error performing mod: right operand has the wrong type (%s)", right.get(0).fhirType())); + throw new PathEngineException(String.format("Error performing mod: right operand has the wrong type (%s)", right.get(0).fhirType()), expr.getStart(), expr.toString()); List result = new ArrayList(); Base l = left.get(0); @@ -2266,12 +2339,12 @@ public class FHIRPathEngine { } } else - throw new PathEngineException(String.format("Error performing mod: left and right operand have incompatible or illegal types (%s, %s)", left.get(0).fhirType(), right.get(0).fhirType())); + throw new PathEngineException(String.format("Error performing mod: left and right operand have incompatible or illegal types (%s, %s)", left.get(0).fhirType(), right.get(0).fhirType()), expr.getStart(), expr.toString()); return result; } - private TypeDetails resolveConstantType(ExecutionTypeContext context, Base constant) throws PathEngineException { + private TypeDetails resolveConstantType(ExecutionTypeContext context, Base constant, ExpressionNode expr) throws PathEngineException { if (constant instanceof BooleanType) return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); else if (constant instanceof IntegerType) @@ -2281,12 +2354,12 @@ public class FHIRPathEngine { else if (constant instanceof Quantity) return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Quantity); else if (constant instanceof FHIRConstant) - return resolveConstantType(context, ((FHIRConstant) constant).getValue()); + return resolveConstantType(context, ((FHIRConstant) constant).getValue(), expr); else return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); } - private TypeDetails resolveConstantType(ExecutionTypeContext context, String s) throws PathEngineException { + private TypeDetails resolveConstantType(ExecutionTypeContext context, String s, ExpressionNode expr) throws PathEngineException { if (s.startsWith("@")) { if (s.startsWith("@T")) return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Time); @@ -2300,11 +2373,11 @@ public class FHIRPathEngine { return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); else if (s.equals("%resource")) { if (context.resource == null) - throw new PathEngineException("%resource cannot be used in this context"); + throw new PathEngineException("%resource cannot be used in this context", expr.getStart(), expr.toString()); return new TypeDetails(CollectionStatus.SINGLETON, context.resource); } else if (s.equals("%rootResource")) { if (context.resource == null) - throw new PathEngineException("%rootResource cannot be used in this context"); + throw new PathEngineException("%rootResource cannot be used in this context", expr.getStart(), expr.toString()); return new TypeDetails(CollectionStatus.SINGLETON, context.resource); } else if (s.equals("%context")) { return context.context; @@ -2319,7 +2392,7 @@ public class FHIRPathEngine { else if (s.startsWith("%`ext-")) return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); else if (hostServices == null) - throw new PathEngineException("Unknown fixed constant type for '"+s+"'"); + throw new PathEngineException("Unknown fixed constant type for '"+s+"'", expr.getStart(), expr.toString()); else return hostServices.resolveConstantType(context.appInfo, s); } @@ -2350,9 +2423,9 @@ public class FHIRPathEngine { return result; } - private TypeDetails executeContextType(ExecutionTypeContext context, String name) throws PathEngineException, DefinitionException { + private TypeDetails executeContextType(ExecutionTypeContext context, String name, ExpressionNode expr) throws PathEngineException, DefinitionException { if (hostServices == null) - throw new PathEngineException("Unable to resolve context reference since no host services are provided"); + throw new PathEngineException("Unable to resolve context reference since no host services are provided", expr.getStart(), expr.toString()); return hostServices.resolveConstantType(context.appInfo, name); } @@ -2360,7 +2433,7 @@ public class FHIRPathEngine { if (atEntry && Character.isUpperCase(exp.getName().charAt(0)) && hashTail(type).equals(exp.getName())) // special case for start up return new TypeDetails(CollectionStatus.SINGLETON, type); TypeDetails result = new TypeDetails(null); - getChildTypesByName(type, exp.getName(), result); + getChildTypesByName(type, exp.getName(), result, exp); return result; } @@ -2390,11 +2463,11 @@ public class FHIRPathEngine { case Exists : return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); case SubsetOf : { - checkParamTypes(exp.getFunction().toCode(), paramTypes, focus); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, focus); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case SupersetOf : { - checkParamTypes(exp.getFunction().toCode(), paramTypes, focus); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, focus); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case IsDistinct : @@ -2414,16 +2487,16 @@ public class FHIRPathEngine { case Aggregate : return anything(focus.getCollectionStatus()); case Item : { - checkOrdered(focus, "item"); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer)); + checkOrdered(focus, "item", exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer)); return focus; } case As : { - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, exp.getParameters().get(0).getName()); } case OfType : { - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, exp.getParameters().get(0).getName()); } case Type : { @@ -2441,31 +2514,31 @@ public class FHIRPathEngine { return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_ClassInfo); } case Is : { - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case Single : return focus.toSingleton(); case First : { - checkOrdered(focus, "first"); + checkOrdered(focus, "first", exp); return focus.toSingleton(); } case Last : { - checkOrdered(focus, "last"); + checkOrdered(focus, "last", exp); return focus.toSingleton(); } case Tail : { - checkOrdered(focus, "tail"); + checkOrdered(focus, "tail", exp); return focus; } case Skip : { - checkOrdered(focus, "skip"); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer)); + checkOrdered(focus, "skip", exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer)); return focus; } case Take : { - checkOrdered(focus, "take"); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer)); + checkOrdered(focus, "take", exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer)); return focus; } case Union : { @@ -2488,76 +2561,76 @@ public class FHIRPathEngine { return types; } case Lower : { - checkContextString(focus, "lower"); + checkContextString(focus, "lower", exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); } case Upper : { - checkContextString(focus, "upper"); + checkContextString(focus, "upper", exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); } case ToChars : { - checkContextString(focus, "toChars"); + checkContextString(focus, "toChars", exp); return new TypeDetails(CollectionStatus.ORDERED, TypeDetails.FP_String); } case IndexOf : { - checkContextString(focus, "indexOf"); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkContextString(focus, "indexOf", exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer); } case Substring : { - checkContextString(focus, "subString"); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer), new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer)); + checkContextString(focus, "subString", exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer), new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); } case StartsWith : { - checkContextString(focus, "startsWith"); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkContextString(focus, "startsWith", exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case EndsWith : { - checkContextString(focus, "endsWith"); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkContextString(focus, "endsWith", exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case Matches : { - checkContextString(focus, "matches"); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkContextString(focus, "matches", exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case ReplaceMatches : { - checkContextString(focus, "replaceMatches"); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String), new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkContextString(focus, "replaceMatches", exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String), new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); } case Contains : { - checkContextString(focus, "contains"); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkContextString(focus, "contains", exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case Replace : { - checkContextString(focus, "replace"); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, "string"), new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkContextString(focus, "replace", exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, "string"), new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); } case Length : { - checkContextPrimitive(focus, "length", false); + checkContextPrimitive(focus, "length", false, exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer); } case Children : - return childTypes(focus, "*"); + return childTypes(focus, "*", exp); case Descendants : - return childTypes(focus, "**"); + return childTypes(focus, "**", exp); case MemberOf : { - checkContextCoded(focus, "memberOf"); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkContextCoded(focus, "memberOf", exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case Trace : { - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return focus; } case Check : { - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return focus; } case Today : @@ -2565,11 +2638,11 @@ public class FHIRPathEngine { case Now : return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_DateTime); case Resolve : { - checkContextReference(focus, "resolve"); + checkContextReference(focus, "resolve", exp); return new TypeDetails(CollectionStatus.SINGLETON, "DomainResource"); } case Extension : { - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, "Extension"); } case AnyTrue: @@ -2585,42 +2658,42 @@ public class FHIRPathEngine { case HtmlChecks : return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); case Alias : - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return anything(CollectionStatus.SINGLETON); case AliasAs : - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return focus; case ToInteger : { - checkContextPrimitive(focus, "toInteger", true); + checkContextPrimitive(focus, "toInteger", true, exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer); } case ToDecimal : { - checkContextPrimitive(focus, "toDecimal", true); + checkContextPrimitive(focus, "toDecimal", true, exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Decimal); } case ToString : { - checkContextPrimitive(focus, "toString", true); + checkContextPrimitive(focus, "toString", true, exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); } case ToQuantity : { - checkContextPrimitive(focus, "toQuantity", true); + checkContextPrimitive(focus, "toQuantity", true, exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Quantity); } case ToBoolean : { - checkContextPrimitive(focus, "toBoolean", false); + checkContextPrimitive(focus, "toBoolean", false, exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case ToDateTime : { - checkContextPrimitive(focus, "toBoolean", false); + checkContextPrimitive(focus, "toBoolean", false, exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_DateTime); } case ToTime : { - checkContextPrimitive(focus, "toBoolean", false); + checkContextPrimitive(focus, "toBoolean", false, exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Time); } case ConvertsToString : case ConvertsToQuantity :{ - checkContextPrimitive(focus, exp.getFunction().toCode(), true); + checkContextPrimitive(focus, exp.getFunction().toCode(), true, exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case ConvertsToInteger : @@ -2628,11 +2701,11 @@ public class FHIRPathEngine { case ConvertsToDateTime : case ConvertsToTime : case ConvertsToBoolean : { - checkContextPrimitive(focus, exp.getFunction().toCode(), false); + checkContextPrimitive(focus, exp.getFunction().toCode(), false, exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case ConformsTo: { - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case Custom : { @@ -2645,7 +2718,7 @@ public class FHIRPathEngine { } - private void checkParamTypes(String funcName, List paramTypes, TypeDetails... typeSet) throws PathEngineException { + private void checkParamTypes(ExpressionNode expr, String funcName, List paramTypes, TypeDetails... typeSet) throws PathEngineException { int i = 0; for (TypeDetails pt : typeSet) { if (i == paramTypes.size()) @@ -2654,47 +2727,47 @@ public class FHIRPathEngine { i++; for (String a : actual.getTypes()) { if (!pt.hasType(worker, a)) - throw new PathEngineException("The parameter type '"+a+"' is not legal for "+funcName+" parameter "+Integer.toString(i)+". expecting "+pt.toString()); + throw new PathEngineException("The parameter type '"+a+"' is not legal for "+funcName+" parameter "+Integer.toString(i)+". expecting "+pt.toString(), expr.getStart(), expr.toString()); } } } - private void checkOrdered(TypeDetails focus, String name) throws PathEngineException { + private void checkOrdered(TypeDetails focus, String name, ExpressionNode expr) throws PathEngineException { if (focus.getCollectionStatus() == CollectionStatus.UNORDERED) - throw new PathEngineException("The function '"+name+"'() can only be used on ordered collections"); + throw new PathEngineException("The function '"+name+"'() can only be used on ordered collections", expr.getStart(), expr.toString()); } - private void checkContextReference(TypeDetails focus, String name) throws PathEngineException { + private void checkContextReference(TypeDetails focus, String name, ExpressionNode expr) throws PathEngineException { if (!focus.hasType(worker, "string") && !focus.hasType(worker, "uri") && !focus.hasType(worker, "Reference") && !focus.hasType(worker, "canonical")) - throw new PathEngineException("The function '"+name+"'() can only be used on string, uri, canonical, Reference"); + throw new PathEngineException("The function '"+name+"'() can only be used on string, uri, canonical, Reference", expr.getStart(), expr.toString()); } - private void checkContextCoded(TypeDetails focus, String name) throws PathEngineException { + private void checkContextCoded(TypeDetails focus, String name, ExpressionNode expr) throws PathEngineException { if (!focus.hasType(worker, "string") && !focus.hasType(worker, "code") && !focus.hasType(worker, "uri") && !focus.hasType(worker, "Coding") && !focus.hasType(worker, "CodeableConcept")) - throw new PathEngineException("The function '"+name+"'() can only be used on string, code, uri, Coding, CodeableConcept"); + throw new PathEngineException("The function '"+name+"'() can only be used on string, code, uri, Coding, CodeableConcept", expr.getStart(), expr.toString()); } - private void checkContextString(TypeDetails focus, String name) throws PathEngineException { + private void checkContextString(TypeDetails focus, String name, ExpressionNode expr) throws PathEngineException { if (!focus.hasType(worker, "string") && !focus.hasType(worker, "code") && !focus.hasType(worker, "uri") && !focus.hasType(worker, "canonical") && !focus.hasType(worker, "id")) - throw new PathEngineException("The function '"+name+"'() can only be used on string, uri, code, id, but found "+focus.describe()); + throw new PathEngineException("The function '"+name+"'() can only be used on string, uri, code, id, but found "+focus.describe(), expr.getStart(), expr.toString()); } - private void checkContextPrimitive(TypeDetails focus, String name, boolean canQty) throws PathEngineException { + private void checkContextPrimitive(TypeDetails focus, String name, boolean canQty, ExpressionNode expr) throws PathEngineException { if (canQty) { if (!focus.hasType(primitiveTypes) && !focus.hasType("Quantity")) - throw new PathEngineException("The function '"+name+"'() can only be used on a Quantity or on "+primitiveTypes.toString()); + throw new PathEngineException("The function '"+name+"'() can only be used on a Quantity or on "+primitiveTypes.toString(), expr.getStart(), expr.toString()); } else if (!focus.hasType(primitiveTypes)) - throw new PathEngineException("The function '"+name+"'() can only be used on "+primitiveTypes.toString()); + throw new PathEngineException("The function '"+name+"'() can only be used on "+primitiveTypes.toString(), expr.getStart(), expr.toString()); } - private TypeDetails childTypes(TypeDetails focus, String mask) throws PathEngineException, DefinitionException { + private TypeDetails childTypes(TypeDetails focus, String mask, ExpressionNode expr) throws PathEngineException, DefinitionException { TypeDetails result = new TypeDetails(CollectionStatus.UNORDERED); for (String f : focus.getTypes()) - getChildTypesByName(f, mask, result); + getChildTypesByName(f, mask, result, expr); return result; } @@ -2823,7 +2896,7 @@ public class FHIRPathEngine { for (Base item : focus) { pc.clear(); pc.add(item); - Equality eq = asBool(execute(changeThis(context, item), pc, exp.getParameters().get(0), true)); + Equality eq = asBool(execute(changeThis(context, item), pc, exp.getParameters().get(0), true), exp); if (eq != Equality.True) { all = false; break; @@ -2918,15 +2991,15 @@ public class FHIRPathEngine { result.add(new StringType(n)); } else { - throw new PathEngineException(String.format("funcReplace() : checking for 2 arguments (pattern, substitution) but found %d items", exp.getParameters().size())); + throw new PathEngineException(String.format("funcReplace() : checking for 2 arguments (pattern, substitution) but found %d items", exp.getParameters().size()), exp.getStart(), exp.toString()); } } else { - throw new PathEngineException(String.format("funcReplace() : checking for 1 string item but found empty item")); + throw new PathEngineException(String.format("funcReplace() : checking for 1 string item but found empty item"), exp.getStart(), exp.toString()); } } else { - throw new PathEngineException(String.format("funcReplace() : checking for 1 string item but found %d items", focus.size())); + throw new PathEngineException(String.format("funcReplace() : checking for 1 string item but found %d items", focus.size()), exp.getStart(), exp.toString()); } return result; } @@ -3043,7 +3116,7 @@ public class FHIRPathEngine { private List funcIif(ExecutionContext context, List focus, ExpressionNode exp) throws FHIRException { List n1 = execute(context, focus, exp.getParameters().get(0), true); - Equality v = asBool(n1); + Equality v = asBool(n1, exp); if (v == Equality.True) return execute(context, focus, exp.getParameters().get(1), true); @@ -3115,7 +3188,7 @@ public class FHIRPathEngine { private List funcSingle(ExecutionContext context, List focus, ExpressionNode exp) throws PathEngineException { if (focus.size() == 1) return focus; - throw new PathEngineException(String.format("Single() : checking for 1 item but found %d items", focus.size())); + throw new PathEngineException(String.format("Single() : checking for 1 item but found %d items", focus.size()), exp.getStart(), exp.toString()); } @@ -3127,10 +3200,10 @@ public class FHIRPathEngine { ExpressionNode texp = exp.getParameters().get(0); if (texp.getKind() != Kind.Name) - throw new PathEngineException("Unsupported Expression type for Parameter on Is"); + throw new PathEngineException("Unsupported Expression type for Parameter on Is", exp.getStart(), exp.toString()); if (texp.getInner() != null) { if (texp.getInner().getKind() != Kind.Name) - throw new PathEngineException("Unsupported Expression type for Parameter on Is"); + throw new PathEngineException("Unsupported Expression type for Parameter on Is", exp.getStart(), exp.toString()); ns = texp.getName(); n = texp.getInner().getName(); } else if (Utilities.existsInList(texp.getName(), "Boolean", "Integer", "Decimal", "String", "DateTime", "Time", "SimpleTypeInfo", "ClassInfo")) { @@ -3375,7 +3448,7 @@ public class FHIRPathEngine { pc.clear(); pc.add(item); List res = execute(context, pc, exp.getParameters().get(0), true); - Equality v = asBool(res); + Equality v = asBool(res, exp); if (v != Equality.False) { all = false; break; @@ -3405,7 +3478,7 @@ public class FHIRPathEngine { pc.clear(); pc.add(item); List res = execute(context, pc, exp.getParameters().get(0), true); - Equality v = asBool(res); + Equality v = asBool(res, exp); if (v == Equality.False) { any = true; break; @@ -3435,7 +3508,7 @@ public class FHIRPathEngine { pc.clear(); pc.add(item); List res = execute(context, pc, exp.getParameters().get(0), true); - Equality v = asBool(res); + Equality v = asBool(res, exp); if (v != Equality.True) { all = false; break; @@ -3465,7 +3538,7 @@ public class FHIRPathEngine { pc.clear(); pc.add(item); List res = execute(context, pc, exp.getParameters().get(0), true); - Equality v = asBool(res); + Equality v = asBool(res, exp); if (v == Equality.True) { any = true; break; @@ -3889,7 +3962,7 @@ public class FHIRPathEngine { for (Base item : focus) { pc.clear(); pc.add(item); - Equality v = asBool(execute(changeThis(context, item), pc, exp.getParameters().get(0), true)); + Equality v = asBool(execute(changeThis(context, item), pc, exp.getParameters().get(0), true), exp); if (v == Equality.True) result.add(item); } @@ -3924,7 +3997,7 @@ public class FHIRPathEngine { private List funcNot(ExecutionContext context, List focus, ExpressionNode exp) throws PathEngineException { List result = new ArrayList(); - Equality v = asBool(focus); + Equality v = asBool(focus, exp); if (v != Equality.Null) result.add(new BooleanType(v != Equality.True)); return result; @@ -3947,9 +4020,9 @@ public class FHIRPathEngine { } - private void getChildTypesByName(String type, String name, TypeDetails result) throws PathEngineException, DefinitionException { + private void getChildTypesByName(String type, String name, TypeDetails result, ExpressionNode expr) throws PathEngineException, DefinitionException { if (Utilities.noString(type)) - throw new PathEngineException("No type provided in BuildToolPathEvaluator.getChildTypesByName"); + throw new PathEngineException("No type provided in BuildToolPathEvaluator.getChildTypesByName", expr.getStart(), expr.toString()); if (type.equals("http://hl7.org/fhir/StructureDefinition/xhtml")) return; if (type.startsWith(Constants.NS_SYSTEM_TYPE)) @@ -3973,7 +4046,7 @@ public class FHIRPathEngine { List sdl = new ArrayList(); ElementDefinitionMatch m = null; if (type.contains("#")) - m = getElementDefinition(sd, type.substring(type.indexOf("#")+1), false); + m = getElementDefinition(sd, type.substring(type.indexOf("#")+1), false, expr); if (m != null && hasDataType(m.definition)) { if (m.fixedType != null) { @@ -4012,11 +4085,11 @@ public class FHIRPathEngine { if (t.getCode().equals("Resource")) { for (String rn : worker.getResourceNames()) { if (!result.hasType(worker, rn)) { - getChildTypesByName(result.addType(rn), "**", result); + getChildTypesByName(result.addType(rn), "**", result, expr); } } } else if (!result.hasType(worker, tn)) { - getChildTypesByName(result.addType(tn), "**", result); + getChildTypesByName(result.addType(tn), "**", result, expr); } } } @@ -4039,7 +4112,7 @@ public class FHIRPathEngine { } else { path = sdi.getSnapshot().getElement().get(0).getPath()+tail+"."+name; - ElementDefinitionMatch ed = getElementDefinition(sdi, path, false); + ElementDefinitionMatch ed = getElementDefinition(sdi, path, false, expr); if (ed != null) { if (!Utilities.noString(ed.getFixedType())) result.addType(ed.getFixedType()); @@ -4088,7 +4161,7 @@ public class FHIRPathEngine { } - private ElementDefinitionMatch getElementDefinition(StructureDefinition sd, String path, boolean allowTypedName) throws PathEngineException { + private ElementDefinitionMatch getElementDefinition(StructureDefinition sd, String path, boolean allowTypedName, ExpressionNode expr) throws PathEngineException { for (ElementDefinition ed : sd.getSnapshot().getElement()) { if (ed.getPath().equals(path)) { if (ed.hasContentReference()) { @@ -4108,15 +4181,15 @@ public class FHIRPathEngine { if (ed.getPath().contains(".") && path.startsWith(ed.getPath()+".") && (ed.getType().size() > 0) && !isAbstractType(ed.getType())) { // now we walk into the type. if (ed.getType().size() > 1) // if there's more than one type, the test above would fail this - throw new PathEngineException("Internal typing issue...."); + throw new PathEngineException("Internal typing issue....", expr.getStart(), expr.toString()); StructureDefinition nsd = worker.fetchResource(StructureDefinition.class, ProfileUtilities.sdNs(ed.getType().get(0).getCode(), worker.getOverrideVersionNs())); if (nsd == null) - throw new PathEngineException("Unknown type "+ed.getType().get(0).getCode()); - return getElementDefinition(nsd, nsd.getId()+path.substring(ed.getPath().length()), allowTypedName); + throw new PathEngineException("Unknown type "+ed.getType().get(0).getCode(), expr.getStart(), expr.toString()); + return getElementDefinition(nsd, nsd.getId()+path.substring(ed.getPath().length()), allowTypedName, expr); } if (ed.hasContentReference() && path.startsWith(ed.getPath()+".")) { ElementDefinitionMatch m = getElementDefinitionById(sd, ed.getContentReference()); - return getElementDefinition(sd, m.definition.getPath()+path.substring(ed.getPath().length()), allowTypedName); + return getElementDefinition(sd, m.definition.getPath()+path.substring(ed.getPath().length()), allowTypedName, expr); } } return null; @@ -4291,13 +4364,13 @@ public class FHIRPathEngine { return path.substring(path.lastIndexOf(".") + 1); } - private Equality asBool(List items) throws PathEngineException { + private Equality asBool(List items, ExpressionNode expr) throws PathEngineException { if (items.size() == 0) return Equality.Null; else if (items.size() == 1) return asBool(items.get(0)); else - throw new PathEngineException("Unable to evaluate as a boolean: "+convertToString(items)); + throw new PathEngineException("Unable to evaluate as a boolean: "+convertToString(items), expr.getStart(), expr.toString()); } private Equality asBoolFromInt(String s) { diff --git a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/NPMPackageGenerator.java b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/NPMPackageGenerator.java index 16577c02a..9b6ce7b4f 100644 --- a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/NPMPackageGenerator.java +++ b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/NPMPackageGenerator.java @@ -58,8 +58,8 @@ import org.hl7.fhir.r4.model.ImplementationGuide.ImplementationGuideDependsOnCom import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; -import org.hl7.fhir.utilities.cache.PackageGenerator.PackageType; -import org.hl7.fhir.utilities.cache.ToolsVersion; +import org.hl7.fhir.utilities.npm.ToolsVersion; +import org.hl7.fhir.utilities.npm.PackageGenerator.PackageType; import com.google.gson.Gson; import com.google.gson.GsonBuilder; diff --git a/org.hl7.fhir.r4/src/test/java/org/hl7/fhir/r4/test/CDARoundTripTests.java b/org.hl7.fhir.r4/src/test/java/org/hl7/fhir/r4/test/CDARoundTripTests.java index ca1be1254..921c4bbba 100644 --- a/org.hl7.fhir.r4/src/test/java/org/hl7/fhir/r4/test/CDARoundTripTests.java +++ b/org.hl7.fhir.r4/src/test/java/org/hl7/fhir/r4/test/CDARoundTripTests.java @@ -8,8 +8,8 @@ import org.hl7.fhir.r4.elementmodel.Element; import org.hl7.fhir.r4.elementmodel.Manager; import org.hl7.fhir.r4.elementmodel.Manager.FhirFormat; import org.hl7.fhir.r4.formats.IParser.OutputStyle; -import org.hl7.fhir.utilities.cache.FilesystemPackageCacheManager; -import org.hl7.fhir.utilities.cache.ToolsVersion; +import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; +import org.hl7.fhir.utilities.npm.ToolsVersion; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; diff --git a/org.hl7.fhir.r4/src/test/java/org/hl7/fhir/r4/test/FHIRPathTests.java b/org.hl7.fhir.r4/src/test/java/org/hl7/fhir/r4/test/FHIRPathTests.java index 0b7f7b0f2..79ea4fcb0 100644 --- a/org.hl7.fhir.r4/src/test/java/org/hl7/fhir/r4/test/FHIRPathTests.java +++ b/org.hl7.fhir.r4/src/test/java/org/hl7/fhir/r4/test/FHIRPathTests.java @@ -205,7 +205,7 @@ public class FHIRPathTests { Assertions.assertTrue(outcome.get(i).equalsDeep(q), String.format("Outcome %d: Value should be %s but was %s", i, v, outcome.get(i).toString())); } else { Assertions.assertTrue(outcome.get(i) instanceof PrimitiveType, String.format("Outcome %d: Value should be a primitive type but was %s", i, outcome.get(i).fhirType())); - Assertions.assertEquals(v, ((PrimitiveType) outcome.get(i)).asStringValue(), String.format("Outcome %d: Value should be %s but was %s for expression %s", i, v, outcome.get(i).toString(), expression)); + Assertions.assertEquals(v, ((PrimitiveType) outcome.get(i)).fpValue(), String.format("Outcome %d: Value should be %s but was %s for expression %s", i, v, ((PrimitiveType) outcome.get(i)).fpValue(), expression)); } } } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/CanonicalResourceManager.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/CanonicalResourceManager.java index 289f7b52d..d9893d099 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/CanonicalResourceManager.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/CanonicalResourceManager.java @@ -220,6 +220,7 @@ public class CanonicalResourceManager { if (enforceUniqueId && map.containsKey(cr.getId())) { drop(cr.getId()); } + // special case logic for UTG support prior to version 5 if (cr.getPackageInfo() != null && cr.getPackageInfo().getId().startsWith("hl7.terminology")) { List> toDrop = new ArrayList<>(); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/IWorkerContext.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/IWorkerContext.java index 8a0593606..72b79b4bd 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/IWorkerContext.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/IWorkerContext.java @@ -67,8 +67,8 @@ import org.hl7.fhir.r5.terminologies.ValueSetExpander.ValueSetExpansionOutcome; import org.hl7.fhir.r5.utils.IResourceValidator; import org.hl7.fhir.utilities.TimeTracker; import org.hl7.fhir.utilities.TranslationServices; -import org.hl7.fhir.utilities.cache.BasePackageCacheManager; -import org.hl7.fhir.utilities.cache.NpmPackage; +import org.hl7.fhir.utilities.npm.BasePackageCacheManager; +import org.hl7.fhir.utilities.npm.NpmPackage; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity; import org.hl7.fhir.utilities.validation.ValidationOptions; diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/SimpleWorkerContext.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/SimpleWorkerContext.java index 207d6ec29..87b8571f7 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/SimpleWorkerContext.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/SimpleWorkerContext.java @@ -81,11 +81,11 @@ import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.TimeTracker; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.VersionUtilities; -import org.hl7.fhir.utilities.cache.BasePackageCacheManager; -import org.hl7.fhir.utilities.cache.FilesystemPackageCacheManager; -import org.hl7.fhir.utilities.cache.NpmPackage; -import org.hl7.fhir.utilities.cache.NpmPackage.PackageResourceInformation; import org.hl7.fhir.utilities.i18n.I18nConstants; +import org.hl7.fhir.utilities.npm.BasePackageCacheManager; +import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; +import org.hl7.fhir.utilities.npm.NpmPackage; +import org.hl7.fhir.utilities.npm.NpmPackage.PackageResourceInformation; import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType; import org.hl7.fhir.utilities.validation.ValidationMessage.Source; diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/BaseDateTimeType.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/BaseDateTimeType.java index 6f68f819d..b9dcb4ace 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/BaseDateTimeType.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/BaseDateTimeType.java @@ -1006,4 +1006,9 @@ public abstract class BaseDateTimeType extends PrimitiveType { } } + @Override + public String fpValue() { + return "@"+primitiveValue(); + } + } \ No newline at end of file diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/ExpressionNode.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/ExpressionNode.java index 3ef89fd7b..253a39b65 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/ExpressionNode.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/ExpressionNode.java @@ -34,6 +34,7 @@ package org.hl7.fhir.r5.model; import java.util.ArrayList; import java.util.List; +import org.hl7.fhir.utilities.SourceLocation; import org.hl7.fhir.utilities.Utilities; public class ExpressionNode { @@ -41,31 +42,7 @@ public class ExpressionNode { public enum Kind { Name, Function, Constant, Group, Unary } - public static class SourceLocation { - private int line; - private int column; - public SourceLocation(int line, int column) { - super(); - this.line = line; - this.column = column; - } - public int getLine() { - return line; - } - public int getColumn() { - return column; - } - public void setLine(int line) { - this.line = line; - } - public void setColumn(int column) { - this.column = column; - } - public String toString() { - return Integer.toString(line)+", "+Integer.toString(column); - } - } public enum Function { Custom, diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/PrimitiveType.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/PrimitiveType.java index b42d3d04e..49ac41018 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/PrimitiveType.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/PrimitiveType.java @@ -248,4 +248,8 @@ public abstract class PrimitiveType extends DataType implements IPrimitiveTyp public boolean hasPrimitiveValue() { return StringUtils.isNotBlank(getValueAsString()); } + + public String fpValue() { + return primitiveValue(); + } } \ No newline at end of file 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 85b238893..94ff7037f 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 @@ -234,6 +234,7 @@ public class ValueSetRenderer extends TerminologyRenderer { } if (doDefinition) { tr.td().b().tx("Definition"); + doLangs = false; } else { // if we're not doing definitions and we don't have too many languages, we'll do them in line if (langs.size() < MAX_LANGS_IN_LINE) { @@ -260,9 +261,9 @@ public class ValueSetRenderer extends TerminologyRenderer { x.para().b().tx("Additional Language Displays"); t = x.table( "codes"); tr = t.tr(); - tdDisp.b().tx("Code"); + tr.td().b().tx("Code"); for (String lang : langs) { - tdDisp.b().addText(describeLang(lang)); + tr.td().b().addText(describeLang(lang)); } for (ValueSetExpansionContainsComponent c : vs.getExpansion().getContains()) { addLanguageRow(c, t, langs); @@ -482,7 +483,6 @@ public class ValueSetRenderer extends TerminologyRenderer { if ("1.0m".equals(v)) return "Jul 1999"; if ("1.0l".equals(v)) return "Jan 1998"; if ("1.0ja".equals(v)) return "Oct 1997"; - return null; } @@ -662,7 +662,9 @@ public class ValueSetRenderer extends TerminologyRenderer { td.i().tx("("+mapping.comp.getComment()+")"); } } - addLangaugesToRow(c, langs, tr); + if (doLangs) { + addLangaugesToRow(c, langs, tr); + } for (ValueSetExpansionContainsComponent cc : c.getContains()) { addExpansionRowToTable(t, cc, i+1, doLevel, doSystem, doDefinition, maps, allCS, langs, doLangs); } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/test/utils/TestingUtilities.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/test/utils/TestingUtilities.java index c7fb031c0..071fc44a9 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/test/utils/TestingUtilities.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/test/utils/TestingUtilities.java @@ -22,8 +22,8 @@ import org.hl7.fhir.utilities.CSFile; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.VersionUtilities; -import org.hl7.fhir.utilities.cache.FilesystemPackageCacheManager; -import org.hl7.fhir.utilities.cache.ToolsVersion; +import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; +import org.hl7.fhir.utilities.npm.ToolsVersion; import org.hl7.fhir.utilities.tests.BaseTestingUtilities; import org.w3c.dom.Document; import org.w3c.dom.Element; diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRLexer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRLexer.java index e08acbefb..4400bcdc8 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRLexer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRLexer.java @@ -34,7 +34,7 @@ import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.r5.model.ExpressionNode; -import org.hl7.fhir.r5.model.ExpressionNode.SourceLocation; +import org.hl7.fhir.utilities.SourceLocation; import org.hl7.fhir.utilities.Utilities; // shared lexer for concrete syntaxes diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java index 5b6c553ff..334b8648f 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java @@ -5,6 +5,7 @@ import java.math.RoundingMode; import java.rmi.server.LoaderHandler; import java.util.ArrayList; import java.util.Base64; +import java.util.Calendar; import java.util.Date; import java.util.EnumSet; import java.util.HashMap; @@ -38,7 +39,6 @@ import org.hl7.fhir.r5.model.ExpressionNode.CollectionStatus; import org.hl7.fhir.r5.model.ExpressionNode.Function; import org.hl7.fhir.r5.model.ExpressionNode.Kind; import org.hl7.fhir.r5.model.ExpressionNode.Operation; -import org.hl7.fhir.r5.model.ExpressionNode.SourceLocation; import org.hl7.fhir.r5.model.Property.PropertyMatcher; import org.hl7.fhir.r5.model.IntegerType; import org.hl7.fhir.r5.model.Property; @@ -58,6 +58,7 @@ import org.hl7.fhir.r5.utils.FHIRPathEngine.IEvaluationContext.FunctionDetails; import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; import org.hl7.fhir.utilities.MergedList; import org.hl7.fhir.utilities.MergedList.MergeNode; +import org.hl7.fhir.utilities.SourceLocation; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.i18n.I18nConstants; import org.hl7.fhir.utilities.validation.ValidationMessage; @@ -509,11 +510,11 @@ public class FHIRPathEngine { } StructureDefinition sd = worker.fetchResource(StructureDefinition.class, ctxt); if (sd == null) { - throw makeException(I18nConstants.FHIRPATH_UNKNOWN_CONTEXT, context); + throw makeException(expr, I18nConstants.FHIRPATH_UNKNOWN_CONTEXT, context); } - ElementDefinitionMatch ed = getElementDefinition(sd, context, true); + ElementDefinitionMatch ed = getElementDefinition(sd, context, true, expr); if (ed == null) { - throw makeException(I18nConstants.FHIRPATH_UNKNOWN_CONTEXT_ELEMENT, context); + throw makeException(expr, I18nConstants.FHIRPATH_UNKNOWN_CONTEXT_ELEMENT, context); } if (ed.fixedType != null) { types = new TypeDetails(CollectionStatus.SINGLETON, ed.fixedType); @@ -530,12 +531,16 @@ public class FHIRPathEngine { return executeType(new ExecutionTypeContext(appContext, resourceType, types, types), types, expr, true); } - private FHIRException makeException(String constName, Object... args) { + private FHIRException makeException(ExpressionNode holder, String constName, Object... args) { String fmt = worker.formatMessage(constName, args); if (location != null) { fmt = fmt + " "+worker.formatMessage(I18nConstants.FHIRPATH_LOCATION, location); } - return new PathEngineException(fmt); + if (holder != null) { + return new PathEngineException(fmt, holder.getStart(), holder.toString()); + } else { + return new PathEngineException(fmt); + } } public TypeDetails check(Object appContext, StructureDefinition sd, String context, ExpressionNode expr) throws FHIRLexerException, PathEngineException, DefinitionException { @@ -544,9 +549,9 @@ public class FHIRPathEngine { if (!context.contains(".")) { types = new TypeDetails(CollectionStatus.SINGLETON, sd.getUrl()); } else { - ElementDefinitionMatch ed = getElementDefinition(sd, context, true); + ElementDefinitionMatch ed = getElementDefinition(sd, context, true, expr); if (ed == null) { - throw makeException(I18nConstants.FHIRPATH_UNKNOWN_CONTEXT_ELEMENT, context); + throw makeException(expr, I18nConstants.FHIRPATH_UNKNOWN_CONTEXT_ELEMENT, context); } if (ed.fixedType != null) { types = new TypeDetails(CollectionStatus.SINGLETON, ed.fixedType); @@ -907,7 +912,7 @@ public class FHIRPathEngine { aliases = new HashMap(aliases); // clone it, since it's going to change } if (focus.size() > 1) { - throw makeException(I18nConstants.FHIRPATH_ALIAS_COLLECTION); + throw makeException(null, I18nConstants.FHIRPATH_ALIAS_COLLECTION); } aliases.put(name, focus.size() == 0 ? null : focus.get(0)); } @@ -956,6 +961,7 @@ public class FHIRPathEngine { wrapper = new ExpressionNode(lexer.nextId()); wrapper.setKind(Kind.Unary); wrapper.setOperation(ExpressionNode.Operation.fromCode(lexer.take())); + wrapper.setStart(lexer.getCurrentLocation()); wrapper.setProximal(proximal); } @@ -967,6 +973,7 @@ public class FHIRPathEngine { wrapper.setKind(Kind.Unary); wrapper.setOperation(ExpressionNode.Operation.fromCode(lexer.getCurrent().substring(0, 1))); wrapper.setProximal(proximal); + wrapper.setStart(lexer.getCurrentLocation()); lexer.setCurrent(lexer.getCurrent().substring(1)); } result.setConstant(processConstant(lexer)); @@ -1354,7 +1361,7 @@ public class FHIRPathEngine { work.addAll(work2); break; case Constant: - Base b = resolveConstant(context, exp.getConstant(), false); + Base b = resolveConstant(context, exp.getConstant(), false, exp); if (b != null) { work.add(b); } @@ -1372,16 +1379,16 @@ public class FHIRPathEngine { ExpressionNode next = exp.getOpNext(); ExpressionNode last = exp; while (next != null) { - List work2 = preOperate(work, last.getOperation()); + List work2 = preOperate(work, last.getOperation(), exp); if (work2 != null) { work = work2; } else if (last.getOperation() == Operation.Is || last.getOperation() == Operation.As) { work2 = executeTypeName(context, focus, next, false); - work = operate(context, work, last.getOperation(), work2); + work = operate(context, work, last.getOperation(), work2, last); } else { work2 = execute(context, focus, next, true); - work = operate(context, work, last.getOperation(), work2); + work = operate(context, work, last.getOperation(), work2, last); // System.out.println("Result of {'"+last.toString()+" "+last.getOperation().toCode()+" "+next.toString()+"'}: "+focus.toString()); } last = next; @@ -1403,7 +1410,7 @@ public class FHIRPathEngine { } - private List preOperate(List left, Operation operation) throws PathEngineException { + private List preOperate(List left, Operation operation, ExpressionNode expr) throws PathEngineException { if (left.size() == 0) { return null; } @@ -1413,7 +1420,7 @@ public class FHIRPathEngine { case Or: return isBoolean(left, true) ? makeBoolean(true) : null; case Implies: - Equality v = asBool(left); + Equality v = asBool(left, expr); return v == Equality.False ? makeBoolean(true) : null; default: return null; @@ -1444,13 +1451,13 @@ public class FHIRPathEngine { } else if (atEntry && exp.getName().equals("$total")) { result.update(anything(CollectionStatus.UNORDERED)); } else if (atEntry && focus == null) { - result.update(executeContextType(context, exp.getName())); + result.update(executeContextType(context, exp.getName(), exp)); } else { for (String s : focus.getTypes()) { result.update(executeType(s, exp, atEntry)); } if (result.hasNoTypes()) { - throw makeException(I18nConstants.FHIRPATH_UNKNOWN_NAME, exp.getName(), focus.describe()); + throw makeException(exp, I18nConstants.FHIRPATH_UNKNOWN_NAME, exp.getName(), focus.describe()); } } break; @@ -1463,7 +1470,7 @@ public class FHIRPathEngine { result.addType(TypeDetails.FP_Quantity); break; case Constant: - result.update(resolveConstantType(context, exp.getConstant())); + result.update(resolveConstantType(context, exp.getConstant(), exp)); break; case Group: result.update(executeType(context, focus, exp.getGroup(), atEntry)); @@ -1484,7 +1491,7 @@ public class FHIRPathEngine { } else { work = executeType(context, focus, next, atEntry); } - result = operateTypes(result, last.getOperation(), work); + result = operateTypes(result, last.getOperation(), work, last); last = next; next = next.getOpNext(); } @@ -1493,21 +1500,21 @@ public class FHIRPathEngine { return result; } - private Base resolveConstant(ExecutionContext context, Base constant, boolean beforeContext) throws PathEngineException { + private Base resolveConstant(ExecutionContext context, Base constant, boolean beforeContext, ExpressionNode expr) throws PathEngineException { if (!(constant instanceof FHIRConstant)) { return constant; } FHIRConstant c = (FHIRConstant) constant; if (c.getValue().startsWith("%")) { - return resolveConstant(context, c.getValue(), beforeContext); + return resolveConstant(context, c.getValue(), beforeContext, expr); } else if (c.getValue().startsWith("@")) { - return processDateConstant(context.appInfo, c.getValue().substring(1)); + return processDateConstant(context.appInfo, c.getValue().substring(1), expr); } else { - throw makeException(I18nConstants.FHIRPATH_UNKNOWN_CONSTANT, c.getValue()); + throw makeException(expr, I18nConstants.FHIRPATH_UNKNOWN_CONSTANT, c.getValue()); } } - private Base processDateConstant(Object appInfo, String value) throws PathEngineException { + private Base processDateConstant(Object appInfo, String value, ExpressionNode expr) throws PathEngineException { String date = null; String time = null; String tz = null; @@ -1555,7 +1562,7 @@ public class FHIRPathEngine { if (date == null) { if (tz != null) { - throw makeException(I18nConstants.FHIRPATH_UNKNOWN_CONTEXT, value); + throw makeException(expr, I18nConstants.FHIRPATH_UNKNOWN_CONTEXT, value); } else { TimeType tt = new TimeType(time); tt.setPrecision(temp); @@ -1571,7 +1578,7 @@ public class FHIRPathEngine { } - private Base resolveConstant(ExecutionContext context, String s, boolean beforeContext) throws PathEngineException { + private Base resolveConstant(ExecutionContext context, String s, boolean beforeContext, ExpressionNode expr) throws PathEngineException { if (s.equals("%sct")) { return new StringType("http://snomed.info/sct").noExtensions(); } else if (s.equals("%loinc")) { @@ -1580,12 +1587,12 @@ public class FHIRPathEngine { return new StringType("http://unitsofmeasure.org").noExtensions(); } else if (s.equals("%resource")) { if (context.focusResource == null) { - throw makeException(I18nConstants.FHIRPATH_CANNOT_USE, "%resource", "no focus resource"); + throw makeException(expr, I18nConstants.FHIRPATH_CANNOT_USE, "%resource", "no focus resource"); } return context.focusResource; } else if (s.equals("%rootResource")) { if (context.rootResource == null) { - throw makeException(I18nConstants.FHIRPATH_CANNOT_USE, "%rootResource", "no focus resource"); + throw makeException(expr, I18nConstants.FHIRPATH_CANNOT_USE, "%rootResource", "no focus resource"); } return context.rootResource; } else if (s.equals("%context")) { @@ -1599,7 +1606,7 @@ public class FHIRPathEngine { } else if (s.startsWith("%`ext-")) { return new StringType("http://hl7.org/fhir/StructureDefinition/"+s.substring(6, s.length()-1)).noExtensions(); } else if (hostServices == null) { - throw makeException(I18nConstants.FHIRPATH_UNKNOWN_CONSTANT, s); + throw makeException(expr, I18nConstants.FHIRPATH_UNKNOWN_CONSTANT, s); } else { return hostServices.resolveConstant(context.appInfo, s.substring(1), beforeContext); } @@ -1660,39 +1667,39 @@ public class FHIRPathEngine { } - private List operate(ExecutionContext context, List left, Operation operation, List right) throws FHIRException { + private List operate(ExecutionContext context, List left, Operation operation, List right, ExpressionNode holder) throws FHIRException { switch (operation) { - case Equals: return opEquals(left, right); - case Equivalent: return opEquivalent(left, right); - case NotEquals: return opNotEquals(left, right); - case NotEquivalent: return opNotEquivalent(left, right); - case LessThan: return opLessThan(left, right); - case Greater: return opGreater(left, right); - case LessOrEqual: return opLessOrEqual(left, right); - case GreaterOrEqual: return opGreaterOrEqual(left, right); - case Union: return opUnion(left, right); - case In: return opIn(left, right); - case MemberOf: return opMemberOf(context, left, right); - case Contains: return opContains(left, right); - case Or: return opOr(left, right); - case And: return opAnd(left, right); - case Xor: return opXor(left, right); - case Implies: return opImplies(left, right); - case Plus: return opPlus(left, right); - case Times: return opTimes(left, right); - case Minus: return opMinus(left, right); - case Concatenate: return opConcatenate(left, right); - case DivideBy: return opDivideBy(left, right); - case Div: return opDiv(left, right); - case Mod: return opMod(left, right); - case Is: return opIs(left, right); - case As: return opAs(left, right); + case Equals: return opEquals(left, right, holder); + case Equivalent: return opEquivalent(left, right, holder); + case NotEquals: return opNotEquals(left, right, holder); + case NotEquivalent: return opNotEquivalent(left, right, holder); + case LessThan: return opLessThan(left, right, holder); + case Greater: return opGreater(left, right, holder); + case LessOrEqual: return opLessOrEqual(left, right, holder); + case GreaterOrEqual: return opGreaterOrEqual(left, right, holder); + case Union: return opUnion(left, right, holder); + case In: return opIn(left, right, holder); + case MemberOf: return opMemberOf(context, left, right, holder); + case Contains: return opContains(left, right, holder); + case Or: return opOr(left, right, holder); + case And: return opAnd(left, right, holder); + case Xor: return opXor(left, right, holder); + case Implies: return opImplies(left, right, holder); + case Plus: return opPlus(left, right, holder); + case Times: return opTimes(left, right, holder); + case Minus: return opMinus(left, right, holder); + case Concatenate: return opConcatenate(left, right, holder); + case DivideBy: return opDivideBy(left, right, holder); + case Div: return opDiv(left, right, holder); + case Mod: return opMod(left, right, holder); + case Is: return opIs(left, right, holder); + case As: return opAs(left, right, holder); default: throw new Error("Not Done Yet: "+operation.toCode()); } } - private List opAs(List left, List right) { + private List opAs(List left, List right, ExpressionNode expr) { List result = new ArrayList<>(); if (right.size() != 1) { return result; @@ -1708,7 +1715,7 @@ public class FHIRPathEngine { } - private List opIs(List left, List right) { + private List opIs(List left, List right, ExpressionNode expr) { List result = new ArrayList(); if (left.size() == 0 || right.size() == 0) { } else if (left.size() != 1 || right.size() != 1) @@ -1727,7 +1734,7 @@ public class FHIRPathEngine { } - private TypeDetails operateTypes(TypeDetails left, Operation operation, TypeDetails right) { + private TypeDetails operateTypes(TypeDetails left, Operation operation, TypeDetails right, ExpressionNode expr) { switch (operation) { case Equals: return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); case Equivalent: return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); @@ -1771,6 +1778,12 @@ public class FHIRPathEngine { result.addType(TypeDetails.FP_Decimal); } else if (left.hasType(worker, "string", "id", "code", "uri") && right.hasType(worker, "string", "id", "code", "uri")) { result.addType(TypeDetails.FP_String); + } else if (left.hasType(worker, "date", "dateTime", "instant")) { + if (right.hasType(worker, "Quantity")) { + result.addType(left.getType()); + } else { + throw new PathEngineException(String.format("Error in date arithmetic: Unable to add type {0} to {1}", right.getType(), left.getType()), expr.getOpStart(), expr.toString()); + } } return result; case Minus: @@ -1781,6 +1794,12 @@ public class FHIRPathEngine { result.addType(TypeDetails.FP_Decimal); } else if (left.hasType(worker, "Quantity") && right.hasType(worker, "Quantity")) { result.addType(TypeDetails.FP_Quantity); + } else if (left.hasType(worker, "date", "dateTime", "instant")) { + if (right.hasType(worker, "Quantity")) { + result.addType(left.getType()); + } else { + throw new PathEngineException(String.format("Error in date arithmetic: Unable to subtract type {0} from {1}", right.getType(), left.getType())); + } } return result; case Div: @@ -1801,7 +1820,7 @@ public class FHIRPathEngine { } - private List opEquals(List left, List right) { + private List opEquals(List left, List right, ExpressionNode expr) { if (left.size() == 0 || right.size() == 0) { return new ArrayList(); } @@ -1830,7 +1849,7 @@ public class FHIRPathEngine { } } - private List opNotEquals(List left, List right) { + private List opNotEquals(List left, List right, ExpressionNode expr) { if (!legacyMode && (left.size() == 0 || right.size() == 0)) { return new ArrayList(); } @@ -2061,7 +2080,7 @@ public class FHIRPathEngine { - private List opEquivalent(List left, List right) throws PathEngineException { + private List opEquivalent(List left, List right, ExpressionNode expr) throws PathEngineException { if (left.size() != right.size()) { return makeBoolean(false); } @@ -2083,7 +2102,7 @@ public class FHIRPathEngine { return makeBoolean(res); } - private List opNotEquivalent(List left, List right) throws PathEngineException { + private List opNotEquivalent(List left, List right, ExpressionNode expr) throws PathEngineException { if (left.size() != right.size()) { return makeBoolean(true); } @@ -2107,7 +2126,7 @@ public class FHIRPathEngine { private final static String[] FHIR_TYPES_STRING = new String[] {"string", "uri", "code", "oid", "id", "uuid", "sid", "markdown", "base64Binary", "canonical", "url"}; - private List opLessThan(List left, List right) throws FHIRException { + private List opLessThan(List left, List right, ExpressionNode expr) throws FHIRException { if (left.size() == 0 || right.size() == 0) return new ArrayList(); @@ -2133,13 +2152,13 @@ public class FHIRPathEngine { return makeBoolean(i < 0); } } else { - throw makeException(I18nConstants.FHIRPATH_CANT_COMPARE, l.fhirType(), r.fhirType()); + throw makeException(expr, I18nConstants.FHIRPATH_CANT_COMPARE, l.fhirType(), r.fhirType()); } } else if (left.size() == 1 && right.size() == 1 && left.get(0).fhirType().equals("Quantity") && right.get(0).fhirType().equals("Quantity") ) { List lUnit = left.get(0).listChildrenByName("code"); List rUnit = right.get(0).listChildrenByName("code"); if (Base.compareDeep(lUnit, rUnit, true)) { - return opLessThan(left.get(0).listChildrenByName("value"), right.get(0).listChildrenByName("value")); + return opLessThan(left.get(0).listChildrenByName("value"), right.get(0).listChildrenByName("value"), expr); } else { if (worker.getUcumService() == null) { return makeBoolean(false); @@ -2148,14 +2167,14 @@ public class FHIRPathEngine { dl.add(qtyToCanonicalDecimal((Quantity) left.get(0))); List dr = new ArrayList(); dr.add(qtyToCanonicalDecimal((Quantity) right.get(0))); - return opLessThan(dl, dr); + return opLessThan(dl, dr, expr); } } } return new ArrayList(); } - private List opGreater(List left, List right) throws FHIRException { + private List opGreater(List left, List right, ExpressionNode expr) throws FHIRException { if (left.size() == 0 || right.size() == 0) return new ArrayList(); if (left.size() == 1 && right.size() == 1 && left.get(0).isPrimitive() && right.get(0).isPrimitive()) { @@ -2180,13 +2199,13 @@ public class FHIRPathEngine { return makeBoolean(i > 0); } } else { - throw makeException(I18nConstants.FHIRPATH_CANT_COMPARE, l.fhirType(), r.fhirType()); + throw makeException(expr, I18nConstants.FHIRPATH_CANT_COMPARE, l.fhirType(), r.fhirType()); } } else if (left.size() == 1 && right.size() == 1 && left.get(0).fhirType().equals("Quantity") && right.get(0).fhirType().equals("Quantity") ) { List lUnit = left.get(0).listChildrenByName("unit"); List rUnit = right.get(0).listChildrenByName("unit"); if (Base.compareDeep(lUnit, rUnit, true)) { - return opGreater(left.get(0).listChildrenByName("value"), right.get(0).listChildrenByName("value")); + return opGreater(left.get(0).listChildrenByName("value"), right.get(0).listChildrenByName("value"), expr); } else { if (worker.getUcumService() == null) { return makeBoolean(false); @@ -2195,14 +2214,14 @@ public class FHIRPathEngine { dl.add(qtyToCanonicalDecimal((Quantity) left.get(0))); List dr = new ArrayList(); dr.add(qtyToCanonicalDecimal((Quantity) right.get(0))); - return opGreater(dl, dr); + return opGreater(dl, dr, expr); } } } return new ArrayList(); } - private List opLessOrEqual(List left, List right) throws FHIRException { + private List opLessOrEqual(List left, List right, ExpressionNode expr) throws FHIRException { if (left.size() == 0 || right.size() == 0) { return new ArrayList(); } @@ -2228,7 +2247,7 @@ public class FHIRPathEngine { return makeBoolean(i <= 0); } } else { - throw makeException(I18nConstants.FHIRPATH_CANT_COMPARE, l.fhirType(), r.fhirType()); + throw makeException(expr, I18nConstants.FHIRPATH_CANT_COMPARE, l.fhirType(), r.fhirType()); } } else if (left.size() == 1 && right.size() == 1 && left.get(0).fhirType().equals("Quantity") && right.get(0).fhirType().equals("Quantity") ) { List lUnits = left.get(0).listChildrenByName("unit"); @@ -2236,7 +2255,7 @@ public class FHIRPathEngine { List rUnits = right.get(0).listChildrenByName("unit"); String runit = rUnits.size() == 1 ? rUnits.get(0).primitiveValue() : null; if ((lunit == null && runit == null) || lunit.equals(runit)) { - return opLessOrEqual(left.get(0).listChildrenByName("value"), right.get(0).listChildrenByName("value")); + return opLessOrEqual(left.get(0).listChildrenByName("value"), right.get(0).listChildrenByName("value"), expr); } else { if (worker.getUcumService() == null) { return makeBoolean(false); @@ -2245,14 +2264,14 @@ public class FHIRPathEngine { dl.add(qtyToCanonicalDecimal((Quantity) left.get(0))); List dr = new ArrayList(); dr.add(qtyToCanonicalDecimal((Quantity) right.get(0))); - return opLessOrEqual(dl, dr); + return opLessOrEqual(dl, dr, expr); } } } return new ArrayList(); } - private List opGreaterOrEqual(List left, List right) throws FHIRException { + private List opGreaterOrEqual(List left, List right, ExpressionNode expr) throws FHIRException { if (left.size() == 0 || right.size() == 0) { return new ArrayList(); } @@ -2278,13 +2297,13 @@ public class FHIRPathEngine { return makeBoolean(i >= 0); } } else { - throw makeException(I18nConstants.FHIRPATH_CANT_COMPARE, l.fhirType(), r.fhirType()); + throw makeException(expr, I18nConstants.FHIRPATH_CANT_COMPARE, l.fhirType(), r.fhirType()); } } else if (left.size() == 1 && right.size() == 1 && left.get(0).fhirType().equals("Quantity") && right.get(0).fhirType().equals("Quantity") ) { List lUnit = left.get(0).listChildrenByName("unit"); List rUnit = right.get(0).listChildrenByName("unit"); if (Base.compareDeep(lUnit, rUnit, true)) { - return opGreaterOrEqual(left.get(0).listChildrenByName("value"), right.get(0).listChildrenByName("value")); + return opGreaterOrEqual(left.get(0).listChildrenByName("value"), right.get(0).listChildrenByName("value"), expr); } else { if (worker.getUcumService() == null) { return makeBoolean(false); @@ -2293,14 +2312,14 @@ public class FHIRPathEngine { dl.add(qtyToCanonicalDecimal((Quantity) left.get(0))); List dr = new ArrayList(); dr.add(qtyToCanonicalDecimal((Quantity) right.get(0))); - return opGreaterOrEqual(dl, dr); + return opGreaterOrEqual(dl, dr, expr); } } } return new ArrayList(); } - private List opMemberOf(ExecutionContext context, List left, List right) throws FHIRException { + private List opMemberOf(ExecutionContext context, List left, List right, ExpressionNode expr) throws FHIRException { boolean ans = false; ValueSet vs = hostServices != null ? hostServices.resolveValueSet(context.appInfo, right.get(0).primitiveValue()) : worker.fetchResource(ValueSet.class, right.get(0).primitiveValue()); if (vs != null) { @@ -2325,7 +2344,7 @@ public class FHIRPathEngine { return makeBoolean(ans); } - private List opIn(List left, List right) throws FHIRException { + private List opIn(List left, List right, ExpressionNode expr) throws FHIRException { if (left.size() == 0) { return new ArrayList(); } @@ -2350,7 +2369,7 @@ public class FHIRPathEngine { return makeBoolean(ans); } - private List opContains(List left, List right) { + private List opContains(List left, List right, ExpressionNode expr) { if (left.size() == 0 || right.size() == 0) { return new ArrayList(); } @@ -2372,21 +2391,21 @@ public class FHIRPathEngine { return makeBoolean(ans); } - private List opPlus(List left, List right) throws PathEngineException { + private List opPlus(List left, List right, ExpressionNode expr) throws PathEngineException { if (left.size() == 0 || right.size() == 0) { return new ArrayList(); } if (left.size() > 1) { - throw makeException(I18nConstants.FHIRPATH_LEFT_VALUE_PLURAL, "+"); + throw makeException(expr, I18nConstants.FHIRPATH_LEFT_VALUE_PLURAL, "+"); } if (!left.get(0).isPrimitive()) { - throw makeException(I18nConstants.FHIRPATH_LEFT_VALUE_WRONG_TYPE, "+", left.get(0).fhirType()); + throw makeException(expr, I18nConstants.FHIRPATH_LEFT_VALUE_WRONG_TYPE, "+", left.get(0).fhirType()); } if (right.size() > 1) { - throw makeException(I18nConstants.FHIRPATH_RIGHT_VALUE_PLURAL, "+"); + throw makeException(expr, I18nConstants.FHIRPATH_RIGHT_VALUE_PLURAL, "+"); } - if (!right.get(0).isPrimitive()) { - throw makeException(I18nConstants.FHIRPATH_RIGHT_VALUE_WRONG_TYPE, "+", right.get(0).fhirType()); + if (!right.get(0).isPrimitive() && !((left.get(0).isDateTime() || "0".equals(left.get(0).primitiveValue()) || left.get(0).hasType("Quantity")) && right.get(0).hasType("Quantity"))) { + throw makeException(expr, I18nConstants.FHIRPATH_RIGHT_VALUE_WRONG_TYPE, "+", right.get(0).fhirType()); } List result = new ArrayList(); @@ -2398,27 +2417,82 @@ public class FHIRPathEngine { result.add(new IntegerType(Integer.parseInt(l.primitiveValue()) + Integer.parseInt(r.primitiveValue()))); } else if (l.hasType("decimal", "integer") && r.hasType("decimal", "integer")) { result.add(new DecimalType(new BigDecimal(l.primitiveValue()).add(new BigDecimal(r.primitiveValue())))); + } else if (l.isDateTime() && r.hasType("Quantity")) { + result.add(dateAdd((BaseDateTimeType) l, (Quantity) r, false, expr)); } else { - throw makeException(I18nConstants.FHIRPATH_OP_INCOMPATIBLE, "+", left.get(0).fhirType(), right.get(0).fhirType()); + throw makeException(expr, I18nConstants.FHIRPATH_OP_INCOMPATIBLE, "+", left.get(0).fhirType(), right.get(0).fhirType()); } return result; } - private List opTimes(List left, List right) throws PathEngineException { + private BaseDateTimeType dateAdd(BaseDateTimeType d, Quantity q, boolean negate, ExpressionNode holder) { + BaseDateTimeType result = (BaseDateTimeType) d.copy(); + + int value = negate ? 0 - q.getValue().intValue() : q.getValue().intValue(); + switch (q.hasCode() ? q.getCode() : q.getUnit()) { + case "years": + case "year": + result.add(Calendar.YEAR, value); + break; + case "a": + throw new PathEngineException(String.format("Error in date arithmetic: attempt to add a definite quantity duration time unit %s", q.getCode())); + case "months": + case "month": + result.add(Calendar.MONTH, value); + break; + case "mo": + throw new PathEngineException(String.format("Error in date arithmetic: attempt to add a definite quantity duration time unit %s", q.getCode()), holder.getOpStart(), holder.toString()); + case "weeks": + case "week": + case "wk": + result.add(Calendar.DAY_OF_MONTH, value * 7); + break; + case "days": + case "day": + case "d": + result.add(Calendar.DAY_OF_MONTH, value); + break; + case "hours": + case "hour": + case "h": + result.add(Calendar.HOUR, value); + break; + case "minutes": + case "minute": + case "min": + result.add(Calendar.MINUTE, value); + break; + case "seconds": + case "second": + case "s": + result.add(Calendar.SECOND, value); + break; + case "milliseconds": + case "millisecond": + case "ms": + result.add(Calendar.MILLISECOND, value); + break; + default: + throw new PathEngineException(String.format("Error in date arithmetic: unrecognized time unit %s", q.getCode())); + } + return result; + } + + private List opTimes(List left, List right, ExpressionNode expr) throws PathEngineException { if (left.size() == 0 || right.size() == 0) { return new ArrayList(); } if (left.size() > 1) { - throw makeException(I18nConstants.FHIRPATH_LEFT_VALUE_PLURAL, "*"); + throw makeException(expr, I18nConstants.FHIRPATH_LEFT_VALUE_PLURAL, "*"); } if (!left.get(0).isPrimitive() && !(left.get(0) instanceof Quantity)) { - throw makeException(I18nConstants.FHIRPATH_LEFT_VALUE_WRONG_TYPE, "*", left.get(0).fhirType()); + throw makeException(expr, I18nConstants.FHIRPATH_LEFT_VALUE_WRONG_TYPE, "*", left.get(0).fhirType()); } if (right.size() > 1) { - throw makeException(I18nConstants.FHIRPATH_RIGHT_VALUE_PLURAL, "*"); + throw makeException(expr, I18nConstants.FHIRPATH_RIGHT_VALUE_PLURAL, "*"); } if (!right.get(0).isPrimitive() && !(right.get(0) instanceof Quantity)) { - throw makeException(I18nConstants.FHIRPATH_RIGHT_VALUE_WRONG_TYPE, "*", right.get(0).fhirType()); + throw makeException(expr, I18nConstants.FHIRPATH_RIGHT_VALUE_WRONG_TYPE, "*", right.get(0).fhirType()); } List result = new ArrayList(); @@ -2437,27 +2511,27 @@ public class FHIRPathEngine { p = worker.getUcumService().multiply(pl, pr); result.add(pairToQty(p)); } catch (UcumException e) { - throw new PathEngineException(e.getMessage(), e); + throw new PathEngineException(e.getMessage(), expr.getOpStart(), expr.toString(), e); } } else { - throw makeException(I18nConstants.FHIRPATH_OP_INCOMPATIBLE, "*", left.get(0).fhirType(), right.get(0).fhirType()); + throw makeException(expr, I18nConstants.FHIRPATH_OP_INCOMPATIBLE, "*", left.get(0).fhirType(), right.get(0).fhirType()); } return result; } - private List opConcatenate(List left, List right) throws PathEngineException { + private List opConcatenate(List left, List right, ExpressionNode expr) throws PathEngineException { if (left.size() > 1) { - throw makeException(I18nConstants.FHIRPATH_LEFT_VALUE_PLURAL, "&"); + throw makeException(expr, I18nConstants.FHIRPATH_LEFT_VALUE_PLURAL, "&"); } if (left.size() > 0 && !left.get(0).hasType(FHIR_TYPES_STRING)) { - throw makeException(I18nConstants.FHIRPATH_LEFT_VALUE_WRONG_TYPE, "&", left.get(0).fhirType()); + throw makeException(expr, I18nConstants.FHIRPATH_LEFT_VALUE_WRONG_TYPE, "&", left.get(0).fhirType()); } if (right.size() > 1) { - throw makeException(I18nConstants.FHIRPATH_RIGHT_VALUE_PLURAL, "&"); + throw makeException(expr, I18nConstants.FHIRPATH_RIGHT_VALUE_PLURAL, "&"); } if (right.size() > 0 && !right.get(0).hasType(FHIR_TYPES_STRING)) { - throw makeException(I18nConstants.FHIRPATH_RIGHT_VALUE_WRONG_TYPE, "&", right.get(0).fhirType()); + throw makeException(expr, I18nConstants.FHIRPATH_RIGHT_VALUE_WRONG_TYPE, "&", right.get(0).fhirType()); } List result = new ArrayList(); @@ -2467,7 +2541,7 @@ public class FHIRPathEngine { return result; } - private List opUnion(List left, List right) { + private List opUnion(List left, List right, ExpressionNode expr) { List result = new ArrayList(); for (Base item : left) { if (!doContains(result, item)) { @@ -2493,9 +2567,9 @@ public class FHIRPathEngine { } - private List opAnd(List left, List right) throws PathEngineException { - Equality l = asBool(left); - Equality r = asBool(right); + private List opAnd(List left, List right, ExpressionNode expr) throws PathEngineException { + Equality l = asBool(left, expr); + Equality r = asBool(right, expr); switch (l) { case False: return makeBoolean(false); case Null: @@ -2518,9 +2592,9 @@ public class FHIRPathEngine { return list.size() == 1 && list.get(0) instanceof BooleanType && ((BooleanType) list.get(0)).booleanValue() == b; } - private List opOr(List left, List right) throws PathEngineException { - Equality l = asBool(left); - Equality r = asBool(right); + private List opOr(List left, List right, ExpressionNode expr) throws PathEngineException { + Equality l = asBool(left, expr); + Equality r = asBool(right, expr); switch (l) { case True: return makeBoolean(true); case Null: @@ -2539,9 +2613,9 @@ public class FHIRPathEngine { return makeNull(); } - private List opXor(List left, List right) throws PathEngineException { - Equality l = asBool(left); - Equality r = asBool(right); + private List opXor(List left, List right, ExpressionNode expr) throws PathEngineException { + Equality l = asBool(left, expr); + Equality r = asBool(right, expr); switch (l) { case True: switch (r) { @@ -2561,13 +2635,13 @@ public class FHIRPathEngine { return makeNull(); } - private List opImplies(List left, List right) throws PathEngineException { - Equality eq = asBool(left); + private List opImplies(List left, List right, ExpressionNode expr) throws PathEngineException { + Equality eq = asBool(left, expr); if (eq == Equality.False) { return makeBoolean(true); } else if (right.size() == 0) { return makeNull(); - } else switch (asBool(right)) { + } else switch (asBool(right, expr)) { case False: return eq == Equality.Null ? makeNull() : makeBoolean(false); case Null: return makeNull(); case True: return makeBoolean(true); @@ -2576,21 +2650,21 @@ public class FHIRPathEngine { } - private List opMinus(List left, List right) throws PathEngineException { + private List opMinus(List left, List right, ExpressionNode expr) throws PathEngineException { if (left.size() == 0 || right.size() == 0) { return new ArrayList(); } if (left.size() > 1) { - throw makeException(I18nConstants.FHIRPATH_LEFT_VALUE_PLURAL, "-"); + throw makeException(expr, I18nConstants.FHIRPATH_LEFT_VALUE_PLURAL, "-"); } if (!left.get(0).isPrimitive() && !left.get(0).hasType("Quantity")) { - throw makeException(I18nConstants.FHIRPATH_LEFT_VALUE_WRONG_TYPE, "-", left.get(0).fhirType()); + throw makeException(expr, I18nConstants.FHIRPATH_LEFT_VALUE_WRONG_TYPE, "-", left.get(0).fhirType()); } if (right.size() > 1) { - throw makeException(I18nConstants.FHIRPATH_RIGHT_VALUE_PLURAL, "-"); + throw makeException(expr, I18nConstants.FHIRPATH_RIGHT_VALUE_PLURAL, "-"); } - if (!right.get(0).isPrimitive() && !right.get(0).hasType("Quantity")) { - throw makeException(I18nConstants.FHIRPATH_RIGHT_VALUE_WRONG_TYPE, "-", right.get(0).fhirType()); + if (!right.get(0).isPrimitive() && !((left.get(0).isDateTime() || "0".equals(left.get(0).primitiveValue()) || left.get(0).hasType("Quantity")) && right.get(0).hasType("Quantity"))) { + throw makeException(expr, I18nConstants.FHIRPATH_RIGHT_VALUE_WRONG_TYPE, "-", right.get(0).fhirType()); } List result = new ArrayList(); @@ -2607,27 +2681,29 @@ public class FHIRPathEngine { Quantity qty = (Quantity) r; result.add(qty.copy().setValue(qty.getValue().abs())); } + } else if (l.isDateTime() && r.hasType("Quantity")) { + result.add(dateAdd((BaseDateTimeType) l, (Quantity) r, true, expr)); } else { - throw makeException(I18nConstants.FHIRPATH_OP_INCOMPATIBLE, "-", left.get(0).fhirType(), right.get(0).fhirType()); + throw makeException(expr, I18nConstants.FHIRPATH_OP_INCOMPATIBLE, "-", left.get(0).fhirType(), right.get(0).fhirType()); } return result; } - private List opDivideBy(List left, List right) throws PathEngineException { + private List opDivideBy(List left, List right, ExpressionNode expr) throws PathEngineException { if (left.size() == 0 || right.size() == 0) { return new ArrayList(); } if (left.size() > 1) { - throw makeException(I18nConstants.FHIRPATH_LEFT_VALUE_PLURAL, "/"); + throw makeException(expr, I18nConstants.FHIRPATH_LEFT_VALUE_PLURAL, "/"); } if (!left.get(0).isPrimitive() && !(left.get(0) instanceof Quantity)) { - throw makeException(I18nConstants.FHIRPATH_LEFT_VALUE_WRONG_TYPE, "/", left.get(0).fhirType()); + throw makeException(expr, I18nConstants.FHIRPATH_LEFT_VALUE_WRONG_TYPE, "/", left.get(0).fhirType()); } if (right.size() > 1) { - throw makeException(I18nConstants.FHIRPATH_RIGHT_VALUE_PLURAL, "/"); + throw makeException(expr, I18nConstants.FHIRPATH_RIGHT_VALUE_PLURAL, "/"); } if (!right.get(0).isPrimitive() && !(right.get(0) instanceof Quantity)) { - throw makeException(I18nConstants.FHIRPATH_RIGHT_VALUE_WRONG_TYPE, "/", right.get(0).fhirType()); + throw makeException(expr, I18nConstants.FHIRPATH_RIGHT_VALUE_WRONG_TYPE, "/", right.get(0).fhirType()); } List result = new ArrayList(); @@ -2654,26 +2730,26 @@ public class FHIRPathEngine { // just return nothing } } else { - throw makeException(I18nConstants.FHIRPATH_OP_INCOMPATIBLE, "/", left.get(0).fhirType(), right.get(0).fhirType()); + throw makeException(expr, I18nConstants.FHIRPATH_OP_INCOMPATIBLE, "/", left.get(0).fhirType(), right.get(0).fhirType()); } return result; } - private List opDiv(List left, List right) throws PathEngineException { + private List opDiv(List left, List right, ExpressionNode expr) throws PathEngineException { if (left.size() == 0 || right.size() == 0) { return new ArrayList(); } if (left.size() > 1) { - throw makeException(I18nConstants.FHIRPATH_LEFT_VALUE_PLURAL, "div"); + throw makeException(expr, I18nConstants.FHIRPATH_LEFT_VALUE_PLURAL, "div"); } if (!left.get(0).isPrimitive() && !(left.get(0) instanceof Quantity)) { - throw makeException(I18nConstants.FHIRPATH_LEFT_VALUE_WRONG_TYPE, "div", left.get(0).fhirType()); + throw makeException(expr, I18nConstants.FHIRPATH_LEFT_VALUE_WRONG_TYPE, "div", left.get(0).fhirType()); } if (right.size() > 1) { - throw makeException(I18nConstants.FHIRPATH_RIGHT_VALUE_PLURAL, "div"); + throw makeException(expr, I18nConstants.FHIRPATH_RIGHT_VALUE_PLURAL, "div"); } if (!right.get(0).isPrimitive() && !(right.get(0) instanceof Quantity)) { - throw makeException(I18nConstants.FHIRPATH_RIGHT_VALUE_WRONG_TYPE, "div", right.get(0).fhirType()); + throw makeException(expr, I18nConstants.FHIRPATH_RIGHT_VALUE_WRONG_TYPE, "div", right.get(0).fhirType()); } List result = new ArrayList(); @@ -2695,25 +2771,25 @@ public class FHIRPathEngine { // just return nothing } } else { - throw makeException(I18nConstants.FHIRPATH_OP_INCOMPATIBLE, "div", left.get(0).fhirType(), right.get(0).fhirType()); + throw makeException(expr, I18nConstants.FHIRPATH_OP_INCOMPATIBLE, "div", left.get(0).fhirType(), right.get(0).fhirType()); } return result; } - private List opMod(List left, List right) throws PathEngineException { + private List opMod(List left, List right, ExpressionNode expr) throws PathEngineException { if (left.size() == 0 || right.size() == 0) { return new ArrayList(); } if (left.size() > 1) { - throw makeException(I18nConstants.FHIRPATH_LEFT_VALUE_PLURAL, "mod"); + throw makeException(expr, I18nConstants.FHIRPATH_LEFT_VALUE_PLURAL, "mod"); } if (!left.get(0).isPrimitive()) { - throw makeException(I18nConstants.FHIRPATH_LEFT_VALUE_WRONG_TYPE, "mod", left.get(0).fhirType()); + throw makeException(expr, I18nConstants.FHIRPATH_LEFT_VALUE_WRONG_TYPE, "mod", left.get(0).fhirType()); } if (right.size() > 1) { - throw makeException(I18nConstants.FHIRPATH_RIGHT_VALUE_PLURAL, "mod"); + throw makeException(expr, I18nConstants.FHIRPATH_RIGHT_VALUE_PLURAL, "mod"); } if (!right.get(0).isPrimitive()) { - throw makeException(I18nConstants.FHIRPATH_RIGHT_VALUE_WRONG_TYPE, "mod", right.get(0).fhirType()); + throw makeException(expr, I18nConstants.FHIRPATH_RIGHT_VALUE_WRONG_TYPE, "mod", right.get(0).fhirType()); } List result = new ArrayList(); @@ -2735,13 +2811,13 @@ public class FHIRPathEngine { throw new PathEngineException(e); } } else { - throw makeException(I18nConstants.FHIRPATH_OP_INCOMPATIBLE, "mod", left.get(0).fhirType(), right.get(0).fhirType()); + throw makeException(expr, I18nConstants.FHIRPATH_OP_INCOMPATIBLE, "mod", left.get(0).fhirType(), right.get(0).fhirType()); } return result; } - private TypeDetails resolveConstantType(ExecutionTypeContext context, Base constant) throws PathEngineException { + private TypeDetails resolveConstantType(ExecutionTypeContext context, Base constant, ExpressionNode expr) throws PathEngineException { if (constant instanceof BooleanType) { return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } else if (constant instanceof IntegerType) { @@ -2751,13 +2827,13 @@ public class FHIRPathEngine { } else if (constant instanceof Quantity) { return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Quantity); } else if (constant instanceof FHIRConstant) { - return resolveConstantType(context, ((FHIRConstant) constant).getValue()); + return resolveConstantType(context, ((FHIRConstant) constant).getValue(), expr); } else { return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); } } - private TypeDetails resolveConstantType(ExecutionTypeContext context, String s) throws PathEngineException { + private TypeDetails resolveConstantType(ExecutionTypeContext context, String s, ExpressionNode expr) throws PathEngineException { if (s.startsWith("@")) { if (s.startsWith("@T")) { return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Time); @@ -2772,12 +2848,12 @@ public class FHIRPathEngine { return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); } else if (s.equals("%resource")) { if (context.resource == null) { - throw makeException(I18nConstants.FHIRPATH_CANNOT_USE, "%resource", "no focus resource"); + throw makeException(expr, I18nConstants.FHIRPATH_CANNOT_USE, "%resource", "no focus resource"); } return new TypeDetails(CollectionStatus.SINGLETON, context.resource); } else if (s.equals("%rootResource")) { if (context.resource == null) { - throw makeException(I18nConstants.FHIRPATH_CANNOT_USE, "%rootResource", "no focus resource"); + throw makeException(expr, I18nConstants.FHIRPATH_CANNOT_USE, "%rootResource", "no focus resource"); } return new TypeDetails(CollectionStatus.SINGLETON, context.resource); } else if (s.equals("%context")) { @@ -2793,7 +2869,7 @@ public class FHIRPathEngine { } else if (s.startsWith("%`ext-")) { return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); } else if (hostServices == null) { - throw makeException(I18nConstants.FHIRPATH_UNKNOWN_CONSTANT, s); + throw makeException(expr, I18nConstants.FHIRPATH_UNKNOWN_CONSTANT, s); } else { return hostServices.resolveConstantType(context.appInfo, s); } @@ -2844,9 +2920,9 @@ public class FHIRPathEngine { } - private TypeDetails executeContextType(ExecutionTypeContext context, String name) throws PathEngineException, DefinitionException { + private TypeDetails executeContextType(ExecutionTypeContext context, String name, ExpressionNode expr) throws PathEngineException, DefinitionException { if (hostServices == null) { - throw makeException(I18nConstants.FHIRPATH_HO_HOST_SERVICES, "Context Reference"); + throw makeException(expr, I18nConstants.FHIRPATH_HO_HOST_SERVICES, "Context Reference"); } return hostServices.resolveConstantType(context.appInfo, name); } @@ -2856,7 +2932,7 @@ public class FHIRPathEngine { return new TypeDetails(CollectionStatus.SINGLETON, type); } TypeDetails result = new TypeDetails(null); - getChildTypesByName(type, exp.getName(), result); + getChildTypesByName(type, exp.getName(), result, exp); return result; } @@ -2886,15 +2962,15 @@ public class FHIRPathEngine { case Not : return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); case Exists : { - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case SubsetOf : { - checkParamTypes(exp.getFunction().toCode(), paramTypes, focus); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, focus); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case SupersetOf : { - checkParamTypes(exp.getFunction().toCode(), paramTypes, focus); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, focus); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case IsDistinct : @@ -2914,16 +2990,16 @@ public class FHIRPathEngine { case Aggregate : return anything(focus.getCollectionStatus()); case Item : { - checkOrdered(focus, "item"); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer)); + checkOrdered(focus, "item", exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer)); return focus; } case As : { - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, exp.getParameters().get(0).getName()); } case OfType : { - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, exp.getParameters().get(0).getName()); } case Type : { @@ -2942,31 +3018,31 @@ public class FHIRPathEngine { } } case Is : { - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case Single : return focus.toSingleton(); case First : { - checkOrdered(focus, "first"); + checkOrdered(focus, "first", exp); return focus.toSingleton(); } case Last : { - checkOrdered(focus, "last"); + checkOrdered(focus, "last", exp); return focus.toSingleton(); } case Tail : { - checkOrdered(focus, "tail"); + checkOrdered(focus, "tail", exp); return focus; } case Skip : { - checkOrdered(focus, "skip"); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer)); + checkOrdered(focus, "skip", exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer)); return focus; } case Take : { - checkOrdered(focus, "take"); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer)); + checkOrdered(focus, "take", exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer)); return focus; } case Union : { @@ -2990,76 +3066,76 @@ public class FHIRPathEngine { return types; } case Lower : { - checkContextString(focus, "lower"); + checkContextString(focus, "lower", exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); } case Upper : { - checkContextString(focus, "upper"); + checkContextString(focus, "upper", exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); } case ToChars : { - checkContextString(focus, "toChars"); + checkContextString(focus, "toChars", exp); return new TypeDetails(CollectionStatus.ORDERED, TypeDetails.FP_String); } case IndexOf : { - checkContextString(focus, "indexOf"); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkContextString(focus, "indexOf", exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer); } case Substring : { - checkContextString(focus, "subString"); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer), new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer)); + checkContextString(focus, "subString", exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer), new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); } case StartsWith : { - checkContextString(focus, "startsWith"); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkContextString(focus, "startsWith", exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case EndsWith : { - checkContextString(focus, "endsWith"); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkContextString(focus, "endsWith", exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case Matches : { - checkContextString(focus, "matches"); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkContextString(focus, "matches", exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case ReplaceMatches : { - checkContextString(focus, "replaceMatches"); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String), new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkContextString(focus, "replaceMatches", exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String), new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); } case Contains : { - checkContextString(focus, "contains"); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkContextString(focus, "contains", exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case Replace : { - checkContextString(focus, "replace"); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, "string"), new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkContextString(focus, "replace", exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, "string"), new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); } case Length : { - checkContextPrimitive(focus, "length", false); + checkContextPrimitive(focus, "length", false, exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer); } case Children : - return childTypes(focus, "*"); + return childTypes(focus, "*", exp); case Descendants : - return childTypes(focus, "**"); + return childTypes(focus, "**", exp); case MemberOf : { - checkContextCoded(focus, "memberOf"); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkContextCoded(focus, "memberOf", exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case Trace : { - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return focus; } case Check : { - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return focus; } case Today : @@ -3067,11 +3143,11 @@ public class FHIRPathEngine { case Now : return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_DateTime); case Resolve : { - checkContextReference(focus, "resolve"); + checkContextReference(focus, "resolve", exp); return new TypeDetails(CollectionStatus.SINGLETON, "DomainResource"); } case Extension : { - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, "Extension"); } case AnyTrue: @@ -3089,62 +3165,62 @@ public class FHIRPathEngine { case HtmlChecks2 : return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); case Alias : - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return anything(CollectionStatus.SINGLETON); case AliasAs : - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return focus; case Encode: - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); case Decode: - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); case Escape: - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); case Unescape: - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); case Trim: return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); case Split: - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); case Join: - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); case ToInteger : { - checkContextPrimitive(focus, "toInteger", true); + checkContextPrimitive(focus, "toInteger", true, exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer); } case ToDecimal : { - checkContextPrimitive(focus, "toDecimal", true); + checkContextPrimitive(focus, "toDecimal", true, exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Decimal); } case ToString : { - checkContextPrimitive(focus, "toString", true); + checkContextPrimitive(focus, "toString", true, exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); } case ToQuantity : { - checkContextPrimitive(focus, "toQuantity", true); + checkContextPrimitive(focus, "toQuantity", true, exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Quantity); } case ToBoolean : { - checkContextPrimitive(focus, "toBoolean", false); + checkContextPrimitive(focus, "toBoolean", false, exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case ToDateTime : { - checkContextPrimitive(focus, "ToDateTime", false); + checkContextPrimitive(focus, "ToDateTime", false, exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_DateTime); } case ToTime : { - checkContextPrimitive(focus, "ToTime", false); + checkContextPrimitive(focus, "ToTime", false, exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Time); } case ConvertsToString : case ConvertsToQuantity :{ - checkContextPrimitive(focus, exp.getFunction().toCode(), true); + checkContextPrimitive(focus, exp.getFunction().toCode(), true, exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case ConvertsToInteger : @@ -3153,28 +3229,28 @@ public class FHIRPathEngine { case ConvertsToDate : case ConvertsToTime : case ConvertsToBoolean : { - checkContextPrimitive(focus, exp.getFunction().toCode(), false); + checkContextPrimitive(focus, exp.getFunction().toCode(), false, exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case ConformsTo: { - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); } case Abs : { - checkContextNumerical(focus, "abs"); + checkContextNumerical(focus, "abs", exp); return new TypeDetails(CollectionStatus.SINGLETON, focus.getTypes()); } case Truncate : case Floor : case Ceiling : { - checkContextDecimal(focus, exp.getFunction().toCode()); + checkContextDecimal(focus, exp.getFunction().toCode(), exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer); } case Round :{ - checkContextDecimal(focus, "round"); + checkContextDecimal(focus, "round", exp); if (paramTypes.size() > 0) { - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer)); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer)); } return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Decimal); } @@ -3182,17 +3258,17 @@ public class FHIRPathEngine { case Exp : case Ln : case Sqrt : { - checkContextNumerical(focus, exp.getFunction().toCode()); + checkContextNumerical(focus, exp.getFunction().toCode(), exp); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Decimal); } case Log : { - checkContextNumerical(focus, exp.getFunction().toCode()); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_NUMBERS)); + checkContextNumerical(focus, exp.getFunction().toCode(), exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_NUMBERS)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Decimal); } case Power : { - checkContextNumerical(focus, exp.getFunction().toCode()); - checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_NUMBERS)); + checkContextNumerical(focus, exp.getFunction().toCode(), exp); + checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_NUMBERS)); return new TypeDetails(CollectionStatus.SINGLETON, focus.getTypes()); } @@ -3206,7 +3282,7 @@ public class FHIRPathEngine { } - private void checkParamTypes(String funcName, List paramTypes, TypeDetails... typeSet) throws PathEngineException { + private void checkParamTypes(ExpressionNode expr, String funcName, List paramTypes, TypeDetails... typeSet) throws PathEngineException { int i = 0; for (TypeDetails pt : typeSet) { if (i == paramTypes.size()) { @@ -3216,65 +3292,65 @@ public class FHIRPathEngine { i++; for (String a : actual.getTypes()) { if (!pt.hasType(worker, a)) { - throw makeException(I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, funcName, i, a, pt.toString()); + throw makeException(expr, I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, funcName, i, a, pt.toString()); } } } } - private void checkOrdered(TypeDetails focus, String name) throws PathEngineException { + private void checkOrdered(TypeDetails focus, String name, ExpressionNode expr) throws PathEngineException { if (focus.getCollectionStatus() == CollectionStatus.UNORDERED) { - throw makeException(I18nConstants.FHIRPATH_ORDERED_ONLY, name); + throw makeException(expr, I18nConstants.FHIRPATH_ORDERED_ONLY, name); } } - private void checkContextReference(TypeDetails focus, String name) throws PathEngineException { + private void checkContextReference(TypeDetails focus, String name, ExpressionNode expr) throws PathEngineException { if (!focus.hasType(worker, "string") && !focus.hasType(worker, "uri") && !focus.hasType(worker, "Reference") && !focus.hasType(worker, "canonical")) { - throw makeException(I18nConstants.FHIRPATH_REFERENCE_ONLY, name, focus.describe()); + throw makeException(expr, I18nConstants.FHIRPATH_REFERENCE_ONLY, name, focus.describe()); } } - private void checkContextCoded(TypeDetails focus, String name) throws PathEngineException { + private void checkContextCoded(TypeDetails focus, String name, ExpressionNode expr) throws PathEngineException { if (!focus.hasType(worker, "string") && !focus.hasType(worker, "code") && !focus.hasType(worker, "uri") && !focus.hasType(worker, "Coding") && !focus.hasType(worker, "CodeableConcept")) { - throw makeException(I18nConstants.FHIRPATH_CODED_ONLY, name, focus.describe()); + throw makeException(expr, I18nConstants.FHIRPATH_CODED_ONLY, name, focus.describe()); } } - private void checkContextString(TypeDetails focus, String name) throws PathEngineException { + private void checkContextString(TypeDetails focus, String name, ExpressionNode expr) throws PathEngineException { if (!focus.hasType(worker, "string") && !focus.hasType(worker, "code") && !focus.hasType(worker, "uri") && !focus.hasType(worker, "canonical") && !focus.hasType(worker, "id")) { - throw makeException(I18nConstants.FHIRPATH_STRING_ONLY, name, focus.describe()); + throw makeException(expr, I18nConstants.FHIRPATH_STRING_ONLY, name, focus.describe()); } } - private void checkContextPrimitive(TypeDetails focus, String name, boolean canQty) throws PathEngineException { + private void checkContextPrimitive(TypeDetails focus, String name, boolean canQty, ExpressionNode expr) throws PathEngineException { if (canQty) { if (!focus.hasType(primitiveTypes) && !focus.hasType("Quantity")) { - throw makeException(I18nConstants.FHIRPATH_PRIMITIVE_ONLY, name, focus.describe(), "Quantity, "+primitiveTypes.toString()); + throw makeException(expr, I18nConstants.FHIRPATH_PRIMITIVE_ONLY, name, focus.describe(), "Quantity, "+primitiveTypes.toString()); } } else if (!focus.hasType(primitiveTypes)) { - throw makeException(I18nConstants.FHIRPATH_PRIMITIVE_ONLY, name, focus.describe(), primitiveTypes.toString()); + throw makeException(expr, I18nConstants.FHIRPATH_PRIMITIVE_ONLY, name, focus.describe(), primitiveTypes.toString()); } } - private void checkContextNumerical(TypeDetails focus, String name) throws PathEngineException { + private void checkContextNumerical(TypeDetails focus, String name, ExpressionNode expr) throws PathEngineException { if (!focus.hasType("integer") && !focus.hasType("decimal") && !focus.hasType("Quantity")) { - throw makeException(I18nConstants.FHIRPATH_NUMERICAL_ONLY, name, focus.describe()); + throw makeException(expr, I18nConstants.FHIRPATH_NUMERICAL_ONLY, name, focus.describe()); } } - private void checkContextDecimal(TypeDetails focus, String name) throws PathEngineException { + private void checkContextDecimal(TypeDetails focus, String name, ExpressionNode expr) throws PathEngineException { if (!focus.hasType("decimal") && !focus.hasType("integer")) { - throw makeException(I18nConstants.FHIRPATH_DECIMAL_ONLY, name, focus.describe()); + throw makeException(expr, I18nConstants.FHIRPATH_DECIMAL_ONLY, name, focus.describe()); } } - private TypeDetails childTypes(TypeDetails focus, String mask) throws PathEngineException, DefinitionException { + private TypeDetails childTypes(TypeDetails focus, String mask, ExpressionNode expr) throws PathEngineException, DefinitionException { TypeDetails result = new TypeDetails(CollectionStatus.UNORDERED); for (String f : focus.getTypes()) { - getChildTypesByName(f, mask, result); + getChildTypesByName(f, mask, result, expr); } return result; } @@ -3394,9 +3470,9 @@ public class FHIRPathEngine { } } - private List funcSqrt(ExecutionContext context, List focus, ExpressionNode exp) { + private List funcSqrt(ExecutionContext context, List focus, ExpressionNode expr) { if (focus.size() != 1) { - throw makeException(I18nConstants.FHIRPATH_FOCUS_PLURAL, "sqrt", focus.size()); + throw makeException(expr, I18nConstants.FHIRPATH_FOCUS_PLURAL, "sqrt", focus.size()); } Base base = focus.get(0); List result = new ArrayList(); @@ -3408,15 +3484,15 @@ public class FHIRPathEngine { // just return nothing } } else { - makeException(I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "sqrt", "(focus)", base.fhirType(), "integer or decimal"); + makeException(expr, I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "sqrt", "(focus)", base.fhirType(), "integer or decimal"); } return result; } - private List funcAbs(ExecutionContext context, List focus, ExpressionNode exp) { + private List funcAbs(ExecutionContext context, List focus, ExpressionNode expr) { if (focus.size() != 1) { - throw makeException(I18nConstants.FHIRPATH_FOCUS_PLURAL, "abs", focus.size()); + throw makeException(expr, I18nConstants.FHIRPATH_FOCUS_PLURAL, "abs", focus.size()); } Base base = focus.get(0); List result = new ArrayList(); @@ -3431,15 +3507,15 @@ public class FHIRPathEngine { Quantity qty = (Quantity) base; result.add(qty.copy().setValue(qty.getValue().abs())); } else { - makeException(I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "abs", "(focus)", base.fhirType(), "integer or decimal"); + makeException(expr, I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "abs", "(focus)", base.fhirType(), "integer or decimal"); } return result; } - private List funcCeiling(ExecutionContext context, List focus, ExpressionNode exp) { + private List funcCeiling(ExecutionContext context, List focus, ExpressionNode expr) { if (focus.size() != 1) { - throw makeException(I18nConstants.FHIRPATH_FOCUS_PLURAL, "ceiling", focus.size()); + throw makeException(expr, I18nConstants.FHIRPATH_FOCUS_PLURAL, "ceiling", focus.size()); } Base base = focus.get(0); List result = new ArrayList(); @@ -3450,14 +3526,14 @@ public class FHIRPathEngine { // just return nothing } } else { - makeException(I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "ceiling", "(focus)", base.fhirType(), "integer or decimal"); + makeException(expr, I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "ceiling", "(focus)", base.fhirType(), "integer or decimal"); } return result; } - private List funcFloor(ExecutionContext context, List focus, ExpressionNode exp) { + private List funcFloor(ExecutionContext context, List focus, ExpressionNode expr) { if (focus.size() != 1) { - throw makeException(I18nConstants.FHIRPATH_FOCUS_PLURAL, "floor", focus.size()); + throw makeException(expr, I18nConstants.FHIRPATH_FOCUS_PLURAL, "floor", focus.size()); } Base base = focus.get(0); List result = new ArrayList(); @@ -3469,15 +3545,15 @@ public class FHIRPathEngine { // just return nothing } } else { - makeException(I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "floor", "(focus)", base.fhirType(), "integer or decimal"); + makeException(expr, I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "floor", "(focus)", base.fhirType(), "integer or decimal"); } return result; } - private List funcExp(ExecutionContext context, List focus, ExpressionNode exp) { + private List funcExp(ExecutionContext context, List focus, ExpressionNode expr) { if (focus.size() != 1) { - throw makeException(I18nConstants.FHIRPATH_FOCUS_PLURAL, "exp", focus.size()); + throw makeException(expr, I18nConstants.FHIRPATH_FOCUS_PLURAL, "exp", focus.size()); } Base base = focus.get(0); List result = new ArrayList(); @@ -3490,15 +3566,15 @@ public class FHIRPathEngine { } } else { - makeException(I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "exp", "(focus)", base.fhirType(), "integer or decimal"); + makeException(expr, I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "exp", "(focus)", base.fhirType(), "integer or decimal"); } return result; } - private List funcLn(ExecutionContext context, List focus, ExpressionNode exp) { + private List funcLn(ExecutionContext context, List focus, ExpressionNode expr) { if (focus.size() != 1) { - throw makeException(I18nConstants.FHIRPATH_FOCUS_PLURAL, "ln", focus.size()); + throw makeException(expr, I18nConstants.FHIRPATH_FOCUS_PLURAL, "ln", focus.size()); } Base base = focus.get(0); List result = new ArrayList(); @@ -3510,22 +3586,22 @@ public class FHIRPathEngine { // just return nothing } } else { - makeException(I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "ln", "(focus)", base.fhirType(), "integer or decimal"); + makeException(expr, I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "ln", "(focus)", base.fhirType(), "integer or decimal"); } return result; } - private List funcLog(ExecutionContext context, List focus, ExpressionNode exp) { + private List funcLog(ExecutionContext context, List focus, ExpressionNode expr) { if (focus.size() != 1) { - throw makeException(I18nConstants.FHIRPATH_FOCUS_PLURAL, "log", focus.size()); + throw makeException(expr, I18nConstants.FHIRPATH_FOCUS_PLURAL, "log", focus.size()); } Base base = focus.get(0); List result = new ArrayList(); if (base.hasType("integer", "decimal", "unsignedInt", "positiveInt")) { - List n1 = execute(context, focus, exp.getParameters().get(0), true); + List n1 = execute(context, focus, expr.getParameters().get(0), true); if (n1.size() != 1) { - throw makeException(I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "log", "0", "Multiple Values", "integer or decimal"); + throw makeException(expr, I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "log", "0", "Multiple Values", "integer or decimal"); } Double e = Double.parseDouble(n1.get(0).primitiveValue()); Double d = Double.parseDouble(base.primitiveValue()); @@ -3535,7 +3611,7 @@ public class FHIRPathEngine { // just return nothing } } else { - makeException(I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "log", "(focus)", base.fhirType(), "integer or decimal"); + makeException(expr, I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "log", "(focus)", base.fhirType(), "integer or decimal"); } return result; } @@ -3544,16 +3620,16 @@ public class FHIRPathEngine { return Math.log(logNumber) / Math.log(base); } - private List funcPower(ExecutionContext context, List focus, ExpressionNode exp) { + private List funcPower(ExecutionContext context, List focus, ExpressionNode expr) { if (focus.size() != 1) { - throw makeException(I18nConstants.FHIRPATH_FOCUS_PLURAL, "power", focus.size()); + throw makeException(expr, I18nConstants.FHIRPATH_FOCUS_PLURAL, "power", focus.size()); } Base base = focus.get(0); List result = new ArrayList(); if (base.hasType("integer", "decimal", "unsignedInt", "positiveInt")) { - List n1 = execute(context, focus, exp.getParameters().get(0), true); + List n1 = execute(context, focus, expr.getParameters().get(0), true); if (n1.size() != 1) { - throw makeException(I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "power", "0", "Multiple Values", "integer or decimal"); + throw makeException(expr, I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "power", "0", "Multiple Values", "integer or decimal"); } Double e = Double.parseDouble(n1.get(0).primitiveValue()); Double d = Double.parseDouble(base.primitiveValue()); @@ -3563,14 +3639,14 @@ public class FHIRPathEngine { // just return nothing } } else { - makeException(I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "power", "(focus)", base.fhirType(), "integer or decimal"); + makeException(expr, I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "power", "(focus)", base.fhirType(), "integer or decimal"); } return result; } - private List funcTruncate(ExecutionContext context, List focus, ExpressionNode exp) { + private List funcTruncate(ExecutionContext context, List focus, ExpressionNode expr) { if (focus.size() != 1) { - throw makeException(I18nConstants.FHIRPATH_FOCUS_PLURAL, "truncate", focus.size()); + throw makeException(expr, I18nConstants.FHIRPATH_FOCUS_PLURAL, "truncate", focus.size()); } Base base = focus.get(0); List result = new ArrayList(); @@ -3581,30 +3657,30 @@ public class FHIRPathEngine { } result.add(new IntegerType(s)); } else { - makeException(I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "sqrt", "(focus)", base.fhirType(), "integer or decimal"); + makeException(expr, I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "sqrt", "(focus)", base.fhirType(), "integer or decimal"); } return result; } - private List funcRound(ExecutionContext context, List focus, ExpressionNode exp) { + private List funcRound(ExecutionContext context, List focus, ExpressionNode expr) { if (focus.size() != 1) { - throw makeException(I18nConstants.FHIRPATH_FOCUS_PLURAL, "round", focus.size()); + throw makeException(expr, I18nConstants.FHIRPATH_FOCUS_PLURAL, "round", focus.size()); } Base base = focus.get(0); List result = new ArrayList(); if (base.hasType("integer", "decimal", "unsignedInt", "positiveInt")) { int i = 0; - if (exp.getParameters().size() == 1) { - List n1 = execute(context, focus, exp.getParameters().get(0), true); + if (expr.getParameters().size() == 1) { + List n1 = execute(context, focus, expr.getParameters().get(0), true); if (n1.size() != 1) { - throw makeException(I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "power", "0", "Multiple Values", "integer"); + throw makeException(expr, I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "power", "0", "Multiple Values", "integer"); } i = Integer.parseInt(n1.get(0).primitiveValue()); } BigDecimal d = new BigDecimal (base.primitiveValue()); result.add(new DecimalType(d.setScale(i, RoundingMode.HALF_UP))); } else { - makeException(I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "round", "(focus)", base.fhirType(), "integer or decimal"); + makeException(expr, I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "round", "(focus)", base.fhirType(), "integer or decimal"); } return result; } @@ -3843,7 +3919,7 @@ public class FHIRPathEngine { for (Base item : focus) { pc.clear(); pc.add(item); - Equality eq = asBool(execute(changeThis(context, item), pc, exp.getParameters().get(0), true)); + Equality eq = asBool(execute(changeThis(context, item), pc, exp.getParameters().get(0), true), exp); if (eq != Equality.True) { all = false; break; @@ -3942,7 +4018,7 @@ public class FHIRPathEngine { } - private List funcReplace(ExecutionContext context, List focus, ExpressionNode exp) throws FHIRException, PathEngineException { + private List funcReplace(ExecutionContext context, List focus, ExpressionNode expr) throws FHIRException, PathEngineException { List result = new ArrayList(); if (focus.size() == 1) { @@ -3950,13 +4026,13 @@ public class FHIRPathEngine { if (Utilities.noString(f)) { result.add(new StringType("")); } else { - String t = convertToString(execute(context, focus, exp.getParameters().get(0), true)); - String r = convertToString(execute(context, focus, exp.getParameters().get(1), true)); + String t = convertToString(execute(context, focus, expr.getParameters().get(0), true)); + String r = convertToString(execute(context, focus, expr.getParameters().get(1), true)); String n = f.replace(t, r); result.add(new StringType(n)); } } else { - throw makeException(I18nConstants.FHIRPATH_NO_COLLECTION, "replace", focus.size()); + throw makeException(expr, I18nConstants.FHIRPATH_NO_COLLECTION, "replace", focus.size()); } return result; } @@ -4049,22 +4125,22 @@ public class FHIRPathEngine { return result; } - private List funcToDateTime(ExecutionContext context, List focus, ExpressionNode exp) { + private List funcToDateTime(ExecutionContext context, List focus, ExpressionNode expr) { // List result = new ArrayList(); // result.add(new BooleanType(convertToBoolean(focus))); // return result; - throw makeException(I18nConstants.FHIRPATH_NOT_IMPLEMENTED, "toDateTime"); + throw makeException(expr, I18nConstants.FHIRPATH_NOT_IMPLEMENTED, "toDateTime"); } - private List funcToTime(ExecutionContext context, List focus, ExpressionNode exp) { + private List funcToTime(ExecutionContext context, List focus, ExpressionNode expr) { // List result = new ArrayList(); // result.add(new BooleanType(convertToBoolean(focus))); // return result; - throw makeException(I18nConstants.FHIRPATH_NOT_IMPLEMENTED, "toTime"); + throw makeException(expr, I18nConstants.FHIRPATH_NOT_IMPLEMENTED, "toTime"); } - private List funcToDecimal(ExecutionContext context, List focus, ExpressionNode exp) { + private List funcToDecimal(ExecutionContext context, List focus, ExpressionNode expr) { String s = convertToString(focus); List result = new ArrayList(); if (Utilities.isDecimal(s, true)) { @@ -4082,7 +4158,7 @@ public class FHIRPathEngine { private List funcIif(ExecutionContext context, List focus, ExpressionNode exp) throws FHIRException { List n1 = execute(context, focus, exp.getParameters().get(0), true); - Equality v = asBool(n1); + Equality v = asBool(n1, exp); if (v == Equality.True) { return execute(context, focus, exp.getParameters().get(1), true); @@ -4157,28 +4233,28 @@ public class FHIRPathEngine { } - private List funcSingle(ExecutionContext context, List focus, ExpressionNode exp) throws PathEngineException { + private List funcSingle(ExecutionContext context, List focus, ExpressionNode expr) throws PathEngineException { if (focus.size() == 1) { return focus; } - throw makeException(I18nConstants.FHIRPATH_NO_COLLECTION, "single", focus.size()); + throw makeException(expr, I18nConstants.FHIRPATH_NO_COLLECTION, "single", focus.size()); } - private List funcIs(ExecutionContext context, List focus, ExpressionNode exp) throws PathEngineException { + private List funcIs(ExecutionContext context, List focus, ExpressionNode expr) throws PathEngineException { if (focus.size() == 0 || focus.size() > 1) { return makeNull(); } String ns = null; String n = null; - ExpressionNode texp = exp.getParameters().get(0); + ExpressionNode texp = expr.getParameters().get(0); if (texp.getKind() != Kind.Name) { - throw makeException(I18nConstants.FHIRPATH_PARAM_WRONG, texp.getKind(), "0", "is"); + throw makeException(expr, I18nConstants.FHIRPATH_PARAM_WRONG, texp.getKind(), "0", "is"); } if (texp.getInner() != null) { if (texp.getInner().getKind() != Kind.Name) { - throw makeException(I18nConstants.FHIRPATH_PARAM_WRONG, texp.getKind(), "1", "is"); + throw makeException(expr, I18nConstants.FHIRPATH_PARAM_WRONG, texp.getKind(), "1", "is"); } ns = texp.getName(); n = texp.getInner().getName(); @@ -4214,13 +4290,13 @@ public class FHIRPathEngine { } - private List funcAs(ExecutionContext context, List focus, ExpressionNode exp) { + private List funcAs(ExecutionContext context, List focus, ExpressionNode expr) { List result = new ArrayList(); String tn; - if (exp.getParameters().get(0).getInner() != null) { - tn = exp.getParameters().get(0).getName()+"."+exp.getParameters().get(0).getInner().getName(); + if (expr.getParameters().get(0).getInner() != null) { + tn = expr.getParameters().get(0).getName()+"."+expr.getParameters().get(0).getInner().getName(); } else { - tn = "FHIR."+exp.getParameters().get(0).getName(); + tn = "FHIR."+expr.getParameters().get(0).getName(); } for (Base b : focus) { if (tn.startsWith("System.")) { @@ -4366,7 +4442,7 @@ public class FHIRPathEngine { if (exp.getParameters().size() == 1) { pc.clear(); pc.add(f); - Equality v = asBool(execute(changeThis(context, f), pc, exp.getParameters().get(0), true)); + Equality v = asBool(execute(changeThis(context, f), pc, exp.getParameters().get(0), true), exp); if (v == Equality.True) { empty = false; } @@ -4461,7 +4537,7 @@ public class FHIRPathEngine { pc.clear(); pc.add(item); List res = execute(context, pc, exp.getParameters().get(0), true); - Equality v = asBool(res); + Equality v = asBool(res, exp); if (v != Equality.False) { all = false; break; @@ -4495,7 +4571,7 @@ public class FHIRPathEngine { pc.clear(); pc.add(item); List res = execute(context, pc, exp.getParameters().get(0), true); - Equality v = asBool(res); + Equality v = asBool(res, exp); if (v == Equality.False) { any = true; break; @@ -4529,7 +4605,7 @@ public class FHIRPathEngine { pc.clear(); pc.add(item); List res = execute(context, pc, exp.getParameters().get(0), true); - Equality v = asBool(res); + Equality v = asBool(res, exp); if (v != Equality.True) { all = false; break; @@ -4562,7 +4638,7 @@ public class FHIRPathEngine { pc.clear(); pc.add(item); List res = execute(context, pc, exp.getParameters().get(0), true); - Equality v = asBool(res); + Equality v = asBool(res, exp); if (v == Equality.True) { any = true; break; @@ -4603,12 +4679,12 @@ public class FHIRPathEngine { return focus; } - private List funcCheck(ExecutionContext context, List focus, ExpressionNode exp) throws FHIRException { - List n1 = execute(context, focus, exp.getParameters().get(0), true); + private List funcCheck(ExecutionContext context, List focus, ExpressionNode expr) throws FHIRException { + List n1 = execute(context, focus, expr.getParameters().get(0), true); if (!convertToBoolean(n1)) { - List n2 = execute(context, focus, exp.getParameters().get(1), true); + List n2 = execute(context, focus, expr.getParameters().get(1), true); String name = n2.get(0).primitiveValue(); - throw makeException(I18nConstants.FHIRPATH_CHECK_FAILED, name); + throw makeException(expr, I18nConstants.FHIRPATH_CHECK_FAILED, name); } return focus; } @@ -4870,15 +4946,15 @@ public class FHIRPathEngine { return result; } - private List funcConformsTo(ExecutionContext context, List focus, ExpressionNode exp) throws FHIRException { + private List funcConformsTo(ExecutionContext context, List focus, ExpressionNode expr) throws FHIRException { if (hostServices == null) { - throw makeException(I18nConstants.FHIRPATH_HO_HOST_SERVICES, "conformsTo"); + throw makeException(expr, I18nConstants.FHIRPATH_HO_HOST_SERVICES, "conformsTo"); } List result = new ArrayList(); if (focus.size() != 1) { result.add(new BooleanType(false).noExtensions()); } else { - String url = convertToString(execute(context, focus, exp.getParameters().get(0), true)); + String url = convertToString(execute(context, focus, expr.getParameters().get(0), true)); result.add(new BooleanType(hostServices.conformsToProfile(context.appInfo, focus.get(0), url)).noExtensions()); } return result; @@ -5041,7 +5117,7 @@ public class FHIRPathEngine { for (Base item : focus) { pc.clear(); pc.add(item); - Equality v = asBool(execute(changeThis(context, item), pc, exp.getParameters().get(0), true)); + Equality v = asBool(execute(changeThis(context, item), pc, exp.getParameters().get(0), true), exp); if (v == Equality.True) { result.add(item); } @@ -5078,7 +5154,7 @@ public class FHIRPathEngine { private List funcNot(ExecutionContext context, List focus, ExpressionNode exp) throws PathEngineException { List result = new ArrayList(); - Equality v = asBool(focus); + Equality v = asBool(focus, exp); if (v != Equality.Null) { result.add(new BooleanType(v != Equality.True)); } @@ -5102,9 +5178,9 @@ public class FHIRPathEngine { } - private void getChildTypesByName(String type, String name, TypeDetails result) throws PathEngineException, DefinitionException { + private void getChildTypesByName(String type, String name, TypeDetails result, ExpressionNode expr) throws PathEngineException, DefinitionException { if (Utilities.noString(type)) { - throw makeException(I18nConstants.FHIRPATH_NO_TYPE, "", "getChildTypesByName"); + throw makeException(expr, I18nConstants.FHIRPATH_NO_TYPE, "", "getChildTypesByName"); } if (type.equals("http://hl7.org/fhir/StructureDefinition/xhtml")) { return; @@ -5127,24 +5203,24 @@ public class FHIRPathEngine { String tail = ""; StructureDefinition sd = worker.fetchResource(StructureDefinition.class, url); if (sd == null) { - throw makeException(I18nConstants.FHIRPATH_NO_TYPE, url, "getChildTypesByName"); + throw makeException(expr, I18nConstants.FHIRPATH_NO_TYPE, url, "getChildTypesByName"); } List sdl = new ArrayList(); ElementDefinitionMatch m = null; if (type.contains("#")) - m = getElementDefinition(sd, type.substring(type.indexOf("#")+1), false); + m = getElementDefinition(sd, type.substring(type.indexOf("#")+1), false, expr); if (m != null && hasDataType(m.definition)) { if (m.fixedType != null) { StructureDefinition dt = worker.fetchResource(StructureDefinition.class, ProfileUtilities.sdNs(m.fixedType, worker.getOverrideVersionNs())); if (dt == null) { - throw makeException(I18nConstants.FHIRPATH_NO_TYPE, ProfileUtilities.sdNs(m.fixedType, worker.getOverrideVersionNs()), "getChildTypesByName"); + throw makeException(expr, I18nConstants.FHIRPATH_NO_TYPE, ProfileUtilities.sdNs(m.fixedType, worker.getOverrideVersionNs()), "getChildTypesByName"); } sdl.add(dt); } else for (TypeRefComponent t : m.definition.getType()) { StructureDefinition dt = worker.fetchResource(StructureDefinition.class, ProfileUtilities.sdNs(t.getCode(), worker.getOverrideVersionNs())); if (dt == null) { - throw makeException(I18nConstants.FHIRPATH_NO_TYPE, ProfileUtilities.sdNs(t.getCode(), worker.getOverrideVersionNs()), "getChildTypesByName"); + throw makeException(expr, I18nConstants.FHIRPATH_NO_TYPE, ProfileUtilities.sdNs(t.getCode(), worker.getOverrideVersionNs()), "getChildTypesByName"); } sdl.add(dt); } @@ -5173,11 +5249,11 @@ public class FHIRPathEngine { if (t.getCode().equals("Resource")) { for (String rn : worker.getResourceNames()) { if (!result.hasType(worker, rn)) { - getChildTypesByName(result.addType(rn), "**", result); + getChildTypesByName(result.addType(rn), "**", result, expr); } } } else if (!result.hasType(worker, tn)) { - getChildTypesByName(result.addType(tn), "**", result); + getChildTypesByName(result.addType(tn), "**", result, expr); } } } @@ -5201,7 +5277,7 @@ public class FHIRPathEngine { } else { path = sdi.getSnapshot().getElement().get(0).getPath()+tail+"."+name; - ElementDefinitionMatch ed = getElementDefinition(sdi, path, isAllowPolymorphicNames()); + ElementDefinitionMatch ed = getElementDefinition(sdi, path, isAllowPolymorphicNames(), expr); if (ed != null) { if (!Utilities.noString(ed.getFixedType())) result.addType(ed.getFixedType()); @@ -5259,7 +5335,7 @@ public class FHIRPathEngine { } - private ElementDefinitionMatch getElementDefinition(StructureDefinition sd, String path, boolean allowTypedName) throws PathEngineException { + private ElementDefinitionMatch getElementDefinition(StructureDefinition sd, String path, boolean allowTypedName, ExpressionNode expr) throws PathEngineException { for (ElementDefinition ed : sd.getSnapshot().getElement()) { if (ed.getPath().equals(path)) { if (ed.hasContentReference()) { @@ -5286,13 +5362,13 @@ public class FHIRPathEngine { } StructureDefinition nsd = worker.fetchResource(StructureDefinition.class, ProfileUtilities.sdNs(ed.getType().get(0).getCode(), worker.getOverrideVersionNs())); if (nsd == null) { - throw makeException(I18nConstants.FHIRPATH_NO_TYPE, ed.getType().get(0).getCode(), "getElementDefinition"); + throw makeException(expr, I18nConstants.FHIRPATH_NO_TYPE, ed.getType().get(0).getCode(), "getElementDefinition"); } - return getElementDefinition(nsd, nsd.getId()+path.substring(ed.getPath().length()), allowTypedName); + return getElementDefinition(nsd, nsd.getId()+path.substring(ed.getPath().length()), allowTypedName, expr); } if (ed.hasContentReference() && path.startsWith(ed.getPath()+".")) { ElementDefinitionMatch m = getElementDefinitionById(sd, ed.getContentReference()); - return getElementDefinition(sd, m.definition.getPath()+path.substring(ed.getPath().length()), allowTypedName); + return getElementDefinition(sd, m.definition.getPath()+path.substring(ed.getPath().length()), allowTypedName, expr); } } return null; @@ -5360,7 +5436,7 @@ public class FHIRPathEngine { if (element.hasSlicing()) { ElementDefinition slice = pickMandatorySlice(sd, element); if (slice == null) { - throw makeException(I18nConstants.FHIRPATH_DISCRIMINATOR_NAME_ALREADY_SLICED, element.getId()); + throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_NAME_ALREADY_SLICED, element.getId()); } element = slice; } @@ -5373,9 +5449,9 @@ public class FHIRPathEngine { // if that's empty, get the children of the type if (childDefinitions.isEmpty()) { - sd = fetchStructureByType(element); + sd = fetchStructureByType(element, expr); if (sd == null) { - throw makeException(I18nConstants.FHIRPATH_DISCRIMINATOR_THIS_CANNOT_FIND, element.getType().get(0).getProfile(), element.getId()); + throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_THIS_CANNOT_FIND, element.getType().get(0).getProfile(), element.getId()); } childDefinitions = profileUtilities.getChildMap(sd, sd.getSnapshot().getElementFirstRep()); } @@ -5389,20 +5465,20 @@ public class FHIRPathEngine { } else if (expr.getKind() == Kind.Function) { if ("resolve".equals(expr.getName())) { if (!element.hasType()) { - throw makeException(I18nConstants.FHIRPATH_DISCRIMINATOR_RESOLVE_NO_TYPE, element.getId()); + throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_RESOLVE_NO_TYPE, element.getId()); } if (element.getType().size() > 1) { - throw makeException(I18nConstants.FHIRPATH_DISCRIMINATOR_RESOLVE_MULTIPLE_TYPES, element.getId()); + throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_RESOLVE_MULTIPLE_TYPES, element.getId()); } if (!element.getType().get(0).hasTarget()) { - throw makeException(I18nConstants.FHIRPATH_DISCRIMINATOR_RESOLVE_NOT_REFERENCE, element.getId(), element.getType().get(0).getCode()+")"); + throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_RESOLVE_NOT_REFERENCE, element.getId(), element.getType().get(0).getCode()+")"); } if (element.getType().get(0).getTargetProfile().size() > 1) { - throw makeException(I18nConstants.FHIRPATH_RESOLVE_DISCRIMINATOR_NO_TARGET, element.getId()); + throw makeException(expr, I18nConstants.FHIRPATH_RESOLVE_DISCRIMINATOR_NO_TARGET, element.getId()); } sd = worker.fetchResource(StructureDefinition.class, element.getType().get(0).getTargetProfile().get(0).getValue()); if (sd == null) { - throw makeException(I18nConstants.FHIRPATH_RESOLVE_DISCRIMINATOR_CANT_FIND, element.getType().get(0).getTargetProfile(), element.getId()); + throw makeException(expr, I18nConstants.FHIRPATH_RESOLVE_DISCRIMINATOR_CANT_FIND, element.getType().get(0).getTargetProfile(), element.getId()); } focus = sd.getSnapshot().getElementFirstRep(); } else if ("extension".equals(expr.getName())) { @@ -5426,13 +5502,13 @@ public class FHIRPathEngine { } } else if ("ofType".equals(expr.getName())) { if (!element.hasType()) { - throw makeException(I18nConstants.FHIRPATH_DISCRIMINATOR_TYPE_NONE, element.getId()); + throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_TYPE_NONE, element.getId()); } if (element.getType().size() > 1) { - throw makeException(I18nConstants.FHIRPATH_DISCRIMINATOR_TYPE_MULTIPLE, element.getId()); + throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_TYPE_MULTIPLE, element.getId()); } if (!element.getType().get(0).hasCode()) { - throw makeException(I18nConstants.FHIRPATH_DISCRIMINATOR_NO_CODE, element.getId()); + throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_NO_CODE, element.getId()); } String atn = element.getType().get(0).getCode(); String stn = expr.getParameters().get(0).getName(); @@ -5441,19 +5517,19 @@ public class FHIRPathEngine { focus = element; } } else { - throw makeException(I18nConstants.FHIRPATH_DISCRIMINATOR_BAD_NAME, expr.getName()); + throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_BAD_NAME, expr.getName()); } } else if (expr.getKind() == Kind.Group) { - throw makeException(I18nConstants.FHIRPATH_DISCRIMINATOR_BAD_SYNTAX_GROUP); + throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_BAD_SYNTAX_GROUP); } else if (expr.getKind() == Kind.Constant) { - throw makeException(I18nConstants.FHIRPATH_DISCRIMINATOR_BAD_SYNTAX_CONST); + throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_BAD_SYNTAX_CONST); } if (focus == null) { if (okToNotResolve) { return null; } else { - throw makeException(I18nConstants.FHIRPATH_DISCRIMINATOR_CANT_FIND, expr.toString()); + throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_CANT_FIND, expr.toString()); } } else if (expr.getInner() == null) { return focus; @@ -5473,15 +5549,15 @@ public class FHIRPathEngine { } - private StructureDefinition fetchStructureByType(ElementDefinition ed) throws DefinitionException { + private StructureDefinition fetchStructureByType(ElementDefinition ed, ExpressionNode expr) throws DefinitionException { if (ed.getType().size() == 0) { - throw makeException(I18nConstants.FHIRPATH_DISCRIMINATOR_NOTYPE, ed.getId()); + throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_NOTYPE, ed.getId()); } if (ed.getType().size() > 1) { - throw makeException(I18nConstants.FHIRPATH_DISCRIMINATOR_MULTIPLE_TYPES, ed.getId()); + throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_MULTIPLE_TYPES, ed.getId()); } if (ed.getType().get(0).getProfile().size() > 1) { - throw makeException(I18nConstants.FHIRPATH_DISCRIMINATOR_MULTIPLE_PROFILES, ed.getId()); + throw makeException(expr, I18nConstants.FHIRPATH_DISCRIMINATOR_MULTIPLE_PROFILES, ed.getId()); } if (ed.getType().get(0).hasProfile()) { return worker.fetchResource(StructureDefinition.class, ed.getType().get(0).getProfile().get(0).getValue()); @@ -5509,7 +5585,7 @@ public class FHIRPathEngine { return path.substring(path.lastIndexOf(".") + 1); } - private Equality asBool(List items) throws PathEngineException { + private Equality asBool(List items, ExpressionNode expr) throws PathEngineException { if (items.size() == 0) { return Equality.Null; } else if (items.size() == 1 && items.get(0).isBooleanPrimitive()) { @@ -5517,7 +5593,7 @@ public class FHIRPathEngine { } else if (items.size() == 1) { return Equality.True; } else { - throw makeException(I18nConstants.FHIRPATH_UNABLE_BOOLEAN, convertToString(items)); + throw makeException(expr, I18nConstants.FHIRPATH_UNABLE_BOOLEAN, convertToString(items)); } } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/NPMPackageGenerator.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/NPMPackageGenerator.java index 0a46a7fcf..5a8d2fb93 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/NPMPackageGenerator.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/NPMPackageGenerator.java @@ -62,9 +62,9 @@ import org.hl7.fhir.r5.model.ImplementationGuide.ImplementationGuideDependsOnCom import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; -import org.hl7.fhir.utilities.cache.NpmPackageIndexBuilder; -import org.hl7.fhir.utilities.cache.PackageGenerator.PackageType; -import org.hl7.fhir.utilities.cache.ToolsVersion; +import org.hl7.fhir.utilities.npm.NpmPackageIndexBuilder; +import org.hl7.fhir.utilities.npm.ToolsVersion; +import org.hl7.fhir.utilities.npm.PackageGenerator.PackageType; import com.google.gson.Gson; import com.google.gson.GsonBuilder; diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/CDARoundTripTests.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/CDARoundTripTests.java index 0573d8740..13408d869 100644 --- a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/CDARoundTripTests.java +++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/CDARoundTripTests.java @@ -13,8 +13,8 @@ import org.hl7.fhir.r5.formats.IParser.OutputStyle; import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.r5.test.utils.TestingUtilities; import org.hl7.fhir.r5.utils.FHIRPathEngine; -import org.hl7.fhir.utilities.cache.FilesystemPackageCacheManager; -import org.hl7.fhir.utilities.cache.ToolsVersion; +import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; +import org.hl7.fhir.utilities.npm.ToolsVersion; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/FHIRPathTests.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/FHIRPathTests.java index 108ea465a..22b3e3e21 100644 --- a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/FHIRPathTests.java +++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/FHIRPathTests.java @@ -176,6 +176,7 @@ public class FHIRPathTests { node = fp.parse(expression); Assertions.assertTrue(fail != TestResultType.SYNTAX, String.format("Expected exception didn't occur parsing %s", expression)); } catch (Exception e) { + System.out.println("Parsing Error: "+e.getMessage()); Assertions.assertTrue(fail == TestResultType.SYNTAX, String.format("Unexpected exception parsing %s: " + e.getMessage(), expression)); } @@ -193,6 +194,7 @@ public class FHIRPathTests { } Assertions.assertTrue(fail != TestResultType.SEMANTICS, String.format("Expected exception didn't occur checking %s", expression)); } catch (Exception e) { + System.out.println("Checking Error: "+e.getMessage()); Assertions.assertTrue(fail == TestResultType.SEMANTICS, String.format("Unexpected exception checking %s: " + e.getMessage(), expression)); node = null; } @@ -203,6 +205,7 @@ public class FHIRPathTests { outcome = fp.evaluate(res, node); Assertions.assertTrue(fail == TestResultType.OK, String.format("Expected exception didn't occur executing %s", expression)); } catch (Exception e) { + System.out.println("Execution Error: "+e.getMessage()); Assertions.assertTrue(fail == TestResultType.EXECUTION, String.format("Unexpected exception executing %s: " + e.getMessage(), expression)); node = null; } @@ -254,11 +257,11 @@ public class FHIRPathTests { Assertions.assertTrue(outcome.get(i).equalsDeep(q), String.format("Outcome %d: Value should be %s but was %s", i, v, outcome.get(i).toString())); } else { Assertions.assertTrue(outcome.get(i) instanceof PrimitiveType, String.format("Outcome %d: Value should be a primitive type but was %s", i, outcome.get(i).fhirType())); - if (!(v.equals(((PrimitiveType) outcome.get(i)).asStringValue()))) { + if (!(v.equals(((PrimitiveType) outcome.get(i)).fpValue()))) { System.out.println(name); - System.out.println(String.format("Outcome %d: Value should be %s but was %s for expression %s", i, v, outcome.get(i).toString(), expression)); + System.out.println(String.format("Outcome %d: Value should be %s but was %s for expression %s", i, v, ((PrimitiveType) outcome.get(i)).fpValue(), expression)); } - Assertions.assertEquals(v, ((PrimitiveType) outcome.get(i)).asStringValue(), String.format("Outcome %d: Value should be %s but was %s for expression %s", i, v, outcome.get(i).toString(), expression)); + Assertions.assertEquals(v, ((PrimitiveType) outcome.get(i)).fpValue(), String.format("Outcome %d: Value should be %s but was %s for expression %s", i, v, ((PrimitiveType) outcome.get(i)).fpValue(), expression)); } } } diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/NpmPackageTests.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/NpmPackageTests.java index c9233871f..b115e42ea 100644 --- a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/NpmPackageTests.java +++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/NpmPackageTests.java @@ -11,7 +11,7 @@ import java.util.zip.ZipInputStream; import org.hl7.fhir.r5.test.utils.TestingUtilities; import org.hl7.fhir.utilities.Utilities; -import org.hl7.fhir.utilities.cache.NpmPackage; +import org.hl7.fhir.utilities.npm.NpmPackage; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/ParsingTests.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/ParsingTests.java index 33bbb6ab8..99a5c4b3c 100644 --- a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/ParsingTests.java +++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/ParsingTests.java @@ -43,9 +43,9 @@ import org.hl7.fhir.r5.utils.IResourceValidator; import org.hl7.fhir.r5.utils.XVerExtensionManager; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; -import org.hl7.fhir.utilities.cache.NpmPackage; -import org.hl7.fhir.utilities.cache.FilesystemPackageCacheManager; -import org.hl7.fhir.utilities.cache.ToolsVersion; +import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; +import org.hl7.fhir.utilities.npm.NpmPackage; +import org.hl7.fhir.utilities.npm.ToolsVersion; import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity; import org.hl7.fhir.utilities.xml.XMLUtil; diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/SnapShotGenerationTests.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/SnapShotGenerationTests.java index b1cdb6b78..d18e7dff1 100644 --- a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/SnapShotGenerationTests.java +++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/SnapShotGenerationTests.java @@ -42,9 +42,9 @@ import org.hl7.fhir.r5.utils.FHIRPathEngine.IEvaluationContext; import org.hl7.fhir.r5.utils.IResourceValidator; import org.hl7.fhir.r5.utils.XVerExtensionManager; import org.hl7.fhir.utilities.Utilities; -import org.hl7.fhir.utilities.cache.NpmPackage; -import org.hl7.fhir.utilities.cache.FilesystemPackageCacheManager; -import org.hl7.fhir.utilities.cache.ToolsVersion; +import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; +import org.hl7.fhir.utilities.npm.NpmPackage; +import org.hl7.fhir.utilities.npm.ToolsVersion; import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity; import org.hl7.fhir.utilities.xml.XMLUtil; diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/StructureMapUtilitiesTest.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/StructureMapUtilitiesTest.java index dc9285a84..f3aa9ea25 100644 --- a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/StructureMapUtilitiesTest.java +++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/StructureMapUtilitiesTest.java @@ -12,8 +12,8 @@ import org.hl7.fhir.r5.model.StructureMap.StructureMapGroupRuleTargetComponent; import org.hl7.fhir.r5.test.utils.TestingUtilities; import org.hl7.fhir.r5.utils.StructureMapUtilities; import org.hl7.fhir.r5.utils.StructureMapUtilities.ITransformerServices; -import org.hl7.fhir.utilities.cache.FilesystemPackageCacheManager; -import org.hl7.fhir.utilities.cache.ToolsVersion; +import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; +import org.hl7.fhir.utilities.npm.ToolsVersion; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/XmlParserTests.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/XmlParserTests.java index bda09cbf3..c7f61adda 100644 --- a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/XmlParserTests.java +++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/XmlParserTests.java @@ -11,8 +11,8 @@ import org.hl7.fhir.r5.formats.IParser.OutputStyle; import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.r5.test.utils.TestingUtilities; import org.hl7.fhir.r5.utils.FHIRPathEngine; -import org.hl7.fhir.utilities.cache.FilesystemPackageCacheManager; -import org.hl7.fhir.utilities.cache.ToolsVersion; +import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; +import org.hl7.fhir.utilities.npm.ToolsVersion; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/exceptions/PathEngineException.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/exceptions/PathEngineException.java index 1eb33bdeb..b26a5ce16 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/exceptions/PathEngineException.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/exceptions/PathEngineException.java @@ -1,5 +1,8 @@ package org.hl7.fhir.exceptions; +import org.hl7.fhir.utilities.SourceLocation; +import org.hl7.fhir.utilities.Utilities; + /* Copyright (c) 2011+, HL7, Inc. All rights reserved. @@ -33,20 +36,62 @@ package org.hl7.fhir.exceptions; public class PathEngineException extends FHIRException { + private static final long serialVersionUID = 31969342112856390L; + private SourceLocation location; + private String expression; + public PathEngineException() { super(); } - public PathEngineException(String message, Throwable cause) { - super(message, cause); - } + public PathEngineException(String message, Throwable cause) { + super(message, cause); + } - public PathEngineException(String message) { - super(message); - } + public PathEngineException(String message) { + super(message); + } - public PathEngineException(Throwable cause) { + public PathEngineException(String message, SourceLocation location, String expression, Throwable cause) { + super(message+rep(location, expression), cause); + } + + public PathEngineException(String message, SourceLocation location, String expression) { + super(message+rep(location, expression)); + } + + private static String rep(SourceLocation loc, String expr) { + if (loc != null) { + if (loc.getLine() == 1) { + return " (@char "+loc.getColumn()+")"; + } else { + return " (@line "+loc.getLine()+" char "+loc.getColumn()+")"; + } + } else if (Utilities.noString(expr)) { // can happen in some contexts... + return " (@~"+expr+")"; + } else { + return ""; + } + } + + public PathEngineException(Throwable cause) { super(cause); } + public String getExpression() { + return expression; + } + + public void setExpression(String expression) { + this.expression = expression; + } + + public SourceLocation getLocation() { + return location; + } + + public void setLocation(SourceLocation location) { + this.location = location; + } + } \ No newline at end of file diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/SourceLocation.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/SourceLocation.java new file mode 100644 index 000000000..5ed864765 --- /dev/null +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/SourceLocation.java @@ -0,0 +1,27 @@ +package org.hl7.fhir.utilities; + +public class SourceLocation { + private int line; + private int column; + public SourceLocation(int line, int column) { + super(); + this.line = line; + this.column = column; + } + public int getLine() { + return line; + } + public int getColumn() { + return column; + } + public void setLine(int line) { + this.line = line; + } + public void setColumn(int column) { + this.column = column; + } + + public String toString() { + return Integer.toString(line)+", "+Integer.toString(column); + } +} diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/VersionUtilities.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/VersionUtilities.java index 83e69ed40..c74687d8b 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/VersionUtilities.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/VersionUtilities.java @@ -4,7 +4,7 @@ import java.util.ArrayList; import java.util.List; import org.hl7.fhir.exceptions.FHIRException; -import org.hl7.fhir.utilities.cache.NpmPackage; +import org.hl7.fhir.utilities.npm.NpmPackage; /* Copyright (c) 2011+, HL7, Inc. diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/BasePackageCacheManager.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/BasePackageCacheManager.java similarity index 99% rename from org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/BasePackageCacheManager.java rename to org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/BasePackageCacheManager.java index 5074396bd..c116eb058 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/BasePackageCacheManager.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/BasePackageCacheManager.java @@ -1,4 +1,4 @@ -package org.hl7.fhir.utilities.cache; +package org.hl7.fhir.utilities.npm; import org.apache.commons.lang3.Validate; import org.hl7.fhir.exceptions.FHIRException; diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/CachingPackageClient.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/CachingPackageClient.java similarity index 97% rename from org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/CachingPackageClient.java rename to org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/CachingPackageClient.java index 571dd59c9..e5812be8f 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/CachingPackageClient.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/CachingPackageClient.java @@ -1,4 +1,4 @@ -package org.hl7.fhir.utilities.cache; +package org.hl7.fhir.utilities.npm; import java.io.File; import java.io.FileInputStream; diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/FilesystemPackageCacheManager.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/FilesystemPackageCacheManager.java similarity index 99% rename from org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/FilesystemPackageCacheManager.java rename to org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/FilesystemPackageCacheManager.java index 4d6b9f11d..66f22cc17 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/FilesystemPackageCacheManager.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/FilesystemPackageCacheManager.java @@ -1,4 +1,4 @@ -package org.hl7.fhir.utilities.cache; +package org.hl7.fhir.utilities.npm; /* Copyright (c) 2011+, HL7, Inc. @@ -40,8 +40,8 @@ import org.hl7.fhir.utilities.IniFile; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.VersionUtilities; -import org.hl7.fhir.utilities.cache.NpmPackage.NpmPackageFolder; import org.hl7.fhir.utilities.json.JSONUtil; +import org.hl7.fhir.utilities.npm.NpmPackage.NpmPackageFolder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/IPackageCacheManager.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/IPackageCacheManager.java similarity index 94% rename from org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/IPackageCacheManager.java rename to org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/IPackageCacheManager.java index eaeeebc48..99e19e511 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/IPackageCacheManager.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/IPackageCacheManager.java @@ -1,4 +1,4 @@ -package org.hl7.fhir.utilities.cache; +package org.hl7.fhir.utilities.npm; import org.hl7.fhir.exceptions.FHIRException; diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/NpmPackage.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/NpmPackage.java similarity index 99% rename from org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/NpmPackage.java rename to org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/NpmPackage.java index f32ef1380..5f1415f62 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/NpmPackage.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/NpmPackage.java @@ -1,4 +1,4 @@ -package org.hl7.fhir.utilities.cache; +package org.hl7.fhir.utilities.npm; /* Copyright (c) 2011+, HL7, Inc. @@ -61,10 +61,10 @@ import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; -import org.hl7.fhir.utilities.cache.NpmPackage.PackageResourceInformationSorter; -import org.hl7.fhir.utilities.cache.PackageGenerator.PackageType; import org.hl7.fhir.utilities.json.JSONUtil; import org.hl7.fhir.utilities.json.JsonTrackingParser; +import org.hl7.fhir.utilities.npm.NpmPackage.PackageResourceInformationSorter; +import org.hl7.fhir.utilities.npm.PackageGenerator.PackageType; import com.google.gson.GsonBuilder; import com.google.gson.JsonArray; diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/NpmPackageIndexBuilder.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/NpmPackageIndexBuilder.java similarity index 97% rename from org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/NpmPackageIndexBuilder.java rename to org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/NpmPackageIndexBuilder.java index 5ae42d265..8d14a449b 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/NpmPackageIndexBuilder.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/NpmPackageIndexBuilder.java @@ -1,4 +1,4 @@ -package org.hl7.fhir.utilities.cache; +package org.hl7.fhir.utilities.npm; import java.io.File; import java.io.IOException; diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/PackageClient.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageClient.java similarity index 99% rename from org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/PackageClient.java rename to org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageClient.java index 16e92ae7b..18f9e434f 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/PackageClient.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageClient.java @@ -1,4 +1,4 @@ -package org.hl7.fhir.utilities.cache; +package org.hl7.fhir.utilities.npm; import com.google.gson.JsonArray; import com.google.gson.JsonElement; diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/PackageGenerator.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageGenerator.java similarity index 99% rename from org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/PackageGenerator.java rename to org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageGenerator.java index a39e537a7..d4d73c1a0 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/PackageGenerator.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageGenerator.java @@ -1,4 +1,4 @@ -package org.hl7.fhir.utilities.cache; +package org.hl7.fhir.utilities.npm; /* Copyright (c) 2011+, HL7, Inc. diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/PackageHacker.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageHacker.java similarity index 97% rename from org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/PackageHacker.java rename to org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageHacker.java index c9c2c7ebe..26e7d9637 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/PackageHacker.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageHacker.java @@ -1,4 +1,4 @@ -package org.hl7.fhir.utilities.cache; +package org.hl7.fhir.utilities.npm; import java.io.File; import java.io.FileInputStream; diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/ToolsVersion.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/ToolsVersion.java similarity index 97% rename from org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/ToolsVersion.java rename to org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/ToolsVersion.java index 7ece6c31e..018ad9c12 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/cache/ToolsVersion.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/ToolsVersion.java @@ -1,4 +1,4 @@ -package org.hl7.fhir.utilities.cache; +package org.hl7.fhir.utilities.npm; /* Copyright (c) 2011+, HL7, Inc. diff --git a/org.hl7.fhir.utilities/src/main/resources/Messages.properties b/org.hl7.fhir.utilities/src/main/resources/Messages.properties index 18bee95a6..f9d145fbf 100644 --- a/org.hl7.fhir.utilities/src/main/resources/Messages.properties +++ b/org.hl7.fhir.utilities/src/main/resources/Messages.properties @@ -133,11 +133,11 @@ Terminology_TX_Code_ValueSetMax = No code provided, and a code must be provided Terminology_TX_Code_ValueSet_Ext = No code provided, and a code should be provided from the value set {0} ({1}) Terminology_TX_Coding_Count = Expected {0} but found {1} coding elements Terminology_TX_Confirm_1 = Could not confirm that the codes provided are in the value set {0} and a code from this value set is required (class = {1}) -Terminology_TX_Confirm_2 = Could not confirm that the codes provided are in the value set {0} and a code should come from this value set unless it has no suitable code (class = {1}) +Terminology_TX_Confirm_2 = Could not confirm that the codes provided are in the value set {0} and a code should come from this value set unless it has no suitable code (the validator cannot judge what is suitable) (class = {1}) Terminology_TX_Confirm_3 = Could not confirm that the codes provided are in the value set {0} and a code is recommended to come from this value set (class = {1}) Terminology_TX_Confirm_4a = The code provided ({2}) is not in the value set {0}, and a code from this value set is required: {1} Terminology_TX_Confirm_4b = The codes provided ({2}) are not in the value set {0}, and a code from this value set is required: {1} -Terminology_TX_Confirm_5 = Could not confirm that the codes provided are in the value set {0}, and a code should come from this value set unless it has no suitable code +Terminology_TX_Confirm_5 = Could not confirm that the codes provided are in the value set {0}, and a code should come from this value set unless it has no suitable code (the validator cannot judge what is suitable) Terminology_TX_Confirm_6 = Could not confirm that the codes provided are in the value set {0}, and a code is recommended to come from this value set Terminology_TX_Display_Wrong = Display should be ''{0}'' Terminology_TX_Error_CodeableConcept = Error {0} validating CodeableConcept @@ -148,16 +148,16 @@ Terminology_TX_NoValid_1 = None of the codes provided are in the value set {0} ( Terminology_TX_NoValid_10 = The code provided is not in the maximum value set {0} ({1}), and a code from this value set is required) (code = {2}#{3}) Terminology_TX_NoValid_11 = The code provided is not in the maximum value set {0} ({1}{2}) Terminology_TX_NoValid_12 = The Coding provided ({2}) is not in the value set {0}, and a code is required from this value set. {1} -Terminology_TX_NoValid_13 = The Coding provided ({2}) is not in the value set {0}, and a code should come from this value set unless it has no suitable code. {1} +Terminology_TX_NoValid_13 = The Coding provided ({2}) is not in the value set {0}, and a code should come from this value set unless it has no suitable code (the validator cannot judge what is suitable). {1} Terminology_TX_NoValid_14 = The Coding provided ({2}) is not in the value set {0}, and a code is recommended to come from this value set. {1} Terminology_TX_NoValid_15 = The value provided (''{0}'') could not be validated in the absence of a terminology server Terminology_TX_NoValid_16 = The value provided (''{0}'') is not in the value set {1} ({2}), and a code is required from this value set){3} -Terminology_TX_NoValid_17 = The value provided (''{0}'') is not in the value set {1} ({2}), and a code should come from this value set unless it has no suitable code){3} +Terminology_TX_NoValid_17 = The value provided (''{0}'') is not in the value set {1} ({2}), and a code should come from this value set unless it has no suitable code and the validator cannot judge what is suitable){3} Terminology_TX_NoValid_18 = The value provided (''{0}'') is not in the value set {1} ({2}), and a code is recommended to come from this value set){3} -Terminology_TX_NoValid_2 = None of the codes provided are in the value set {0} ({1}), and a code should come from this value set unless it has no suitable code) (codes = {2}) +Terminology_TX_NoValid_2 = None of the codes provided are in the value set {0} ({1}), and a code should come from this value set unless it has no suitable code and the validator cannot judge what is suitable) (codes = {2}) Terminology_TX_NoValid_3 = None of the codes provided are in the value set {0} ({1}), and a code is recommended to come from this value set) (codes = {2}) Terminology_TX_NoValid_4 = The Coding provided ({2}) is not in the value set {0}, and a code is required from this value set {1} -Terminology_TX_NoValid_5 = The Coding provided ({2}) is not in the value set {0}, and a code should come from this value set unless it has no suitable code {1} +Terminology_TX_NoValid_5 = The Coding provided ({2}) is not in the value set {0}, and a code should come from this value set unless it has no suitable code (the validator cannot judge what is suitable) {1} Terminology_TX_NoValid_6 = The Coding provided ({2}) is not in the value set {0}, and a code is recommended to come from this value set {1} Terminology_TX_NoValid_7 = None of the codes provided could be validated against the maximum value set {0} ({1}), (error = {2}) Terminology_TX_NoValid_8 = None of the codes provided are in the maximum value set {0} ({1}), and a code from this value set is required) (codes = {2}) diff --git a/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/tests/CachingPackageClientTests.java b/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/tests/CachingPackageClientTests.java index 2e897e910..a9d592118 100644 --- a/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/tests/CachingPackageClientTests.java +++ b/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/tests/CachingPackageClientTests.java @@ -1,7 +1,7 @@ package org.hl7.fhir.utilities.tests; -import org.hl7.fhir.utilities.cache.CachingPackageClient; -import org.hl7.fhir.utilities.cache.PackageClient.PackageInfo; +import org.hl7.fhir.utilities.npm.CachingPackageClient; +import org.hl7.fhir.utilities.npm.PackageClient.PackageInfo; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; diff --git a/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/tests/PackageCacheTests.java b/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/tests/PackageCacheTests.java index 8e8289fbd..05d38d4d8 100644 --- a/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/tests/PackageCacheTests.java +++ b/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/tests/PackageCacheTests.java @@ -1,9 +1,9 @@ package org.hl7.fhir.utilities.tests; import org.hl7.fhir.utilities.Utilities; -import org.hl7.fhir.utilities.cache.NpmPackage; -import org.hl7.fhir.utilities.cache.FilesystemPackageCacheManager; -import org.hl7.fhir.utilities.cache.ToolsVersion; +import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; +import org.hl7.fhir.utilities.npm.NpmPackage; +import org.hl7.fhir.utilities.npm.ToolsVersion; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/BaseValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/BaseValidator.java index c36db51d3..8e7b585a7 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/BaseValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/BaseValidator.java @@ -529,6 +529,21 @@ public class BaseValidator { return thePass; } + /** + * Test a rule and add a {@link IssueSeverity#WARNING} validation message if the validation fails + * + * @param thePass + * Set this parameter to false if the validation does not pass + * @return Returns thePass (in other words, returns true if the rule did not fail validation) + */ + protected boolean warningOrHint(List errors, IssueType type, String path, boolean thePass, boolean warning, String msg, Object... theMessageArguments) { + if (!thePass) { + String message = context.formatMessage(msg, theMessageArguments); + addValidationMessage(errors, type, -1, -1, path, message, warning ? IssueSeverity.WARNING : IssueSeverity.INFORMATION, null); + } + return thePass; + } + /** * Test a rule and add a {@link IssueSeverity#WARNING} validation message if the validation fails * 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 d01ed9700..506c54680 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 @@ -34,7 +34,13 @@ import org.hl7.fhir.r5.utils.*; import org.hl7.fhir.r5.utils.IResourceValidator.*; import org.hl7.fhir.r5.utils.StructureMapUtilities.ITransformerServices; import org.hl7.fhir.utilities.i18n.I18nConstants; +import org.hl7.fhir.utilities.npm.BasePackageCacheManager; +import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; +import org.hl7.fhir.utilities.npm.NpmPackage; +import org.hl7.fhir.utilities.npm.PackageClient; +import org.hl7.fhir.utilities.npm.ToolsVersion; import org.hl7.fhir.validation.BaseValidator.ValidationControl; +import org.hl7.fhir.validation.Validator.QuestionnaireMode; import org.hl7.fhir.validation.cli.services.StandAloneValidatorFetcher.IPackageInstaller; import org.hl7.fhir.validation.instance.InstanceValidator; import org.hl7.fhir.utilities.IniFile; @@ -42,11 +48,6 @@ import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.TimeTracker; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.VersionUtilities; -import org.hl7.fhir.utilities.cache.NpmPackage; -import org.hl7.fhir.utilities.cache.PackageClient; -import org.hl7.fhir.utilities.cache.BasePackageCacheManager; -import org.hl7.fhir.utilities.cache.FilesystemPackageCacheManager; -import org.hl7.fhir.utilities.cache.ToolsVersion; import org.hl7.fhir.utilities.i18n.I18nBase; import org.hl7.fhir.utilities.i18n.I18nConstants; import org.hl7.fhir.utilities.validation.ValidationMessage; @@ -311,6 +312,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst private boolean showTimes; private List bundleValidationRules = new ArrayList<>(); private Map validationControl = new HashMap<>(); + private QuestionnaireMode questionnaireMode; private class AsteriskFilter implements FilenameFilter { String dir; @@ -531,7 +533,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst v = src.substring(src.indexOf("|")+1); src = src.substring(0, src.indexOf("|")); } - String pid = pcm.getPackageId(src); + String pid = explore ? pcm.getPackageId(src) : null; if (!Utilities.noString(pid)) return fetchByPackage(pid+(v == null ? "" : "#"+v)); else @@ -563,7 +565,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst } else if ((src.matches(FilesystemPackageCacheManager.PACKAGE_REGEX) || src.matches(FilesystemPackageCacheManager.PACKAGE_VERSION_REGEX)) && !src.endsWith(".zip") && !src.endsWith(".tgz")) { return fetchByPackage(src); } - throw new FHIRException("Unable to find/resolve/read -ig "+src); + throw new FHIRException("Unable to find/resolve/read "+(explore ? "-ig " : "")+src); } private Map loadIgSourceForVersion(String src, boolean recursive, boolean explore, VersionSourceInformation versions) throws FHIRException, IOException { @@ -642,18 +644,26 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst // ok, having tried all that... now we'll just try to access it directly byte[] cnt; - if (stream == null) - cnt = fetchFromUrlSpecific(src, "application/json", true); - else + List errors = new ArrayList<>(); + if (stream != null) { cnt = TextFile.streamToBytes(stream); - + } else { + cnt = fetchFromUrlSpecific(src, "application/json", true, errors); + if (cnt == null) { + cnt = fetchFromUrlSpecific(src, "application/xml", true, errors); + } + } + if (cnt == null) { + throw new FHIRException("Unable to fetch content from "+src+" ("+errors.toString()+")"); + + } FhirFormat fmt = checkIsResource(cnt, src); if (fmt != null) { Map res = new HashMap(); res.put(Utilities.changeFileExt(src, "."+fmt.getExtension()), cnt); return res; } - throw new FHIRException("Unable to find/resolve/read -ig "+src); + throw new FHIRException("Unable to read content from "+src+": cannot determine format"); } private Map fetchVersionFromUrl(String src, boolean explore, VersionSourceInformation versions) throws FHIRException, IOException { @@ -687,7 +697,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst // ok, having tried all that... now we'll just try to access it directly byte[] cnt; if (stream == null) - cnt = fetchFromUrlSpecific(src, "application/json", true); + cnt = fetchFromUrlSpecific(src, "application/json", true, null); else cnt = TextFile.streamToBytes(stream); @@ -697,7 +707,20 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst res.put(Utilities.changeFileExt(src, "."+fmt.getExtension()), cnt); return res; } - throw new FHIRException("Unable to find/resolve/read -ig "+src); + String fn = Utilities.path("[tmp]", "fetch-resource-error-content.bin"); + TextFile.bytesToFile(cnt, fn); + System.out.println("Error Fetching "+src); + System.out.println("Some content was found, saved to "+fn); + System.out.println("1st 100 bytes = "+presentForDebugging(cnt)); + throw new FHIRException("Unable to find/resolve/read "+(explore ? "-ig " : "")+src); + } + + private String presentForDebugging(byte[] cnt) { + StringBuilder b = new StringBuilder(); + for (int i = 0; i < Integer.min(cnt.length, 50); i++) { + b.append(Integer.toHexString(cnt[i])); + } + return b.toString(); } private InputStream fetchFromUrlSpecific(String source, boolean optional) throws FHIRException, IOException { @@ -713,13 +736,24 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst } } - private byte[] fetchFromUrlSpecific(String source, String contentType, boolean optional) throws FHIRException, IOException { + private byte[] fetchFromUrlSpecific(String source, String contentType, boolean optional, List errors) throws FHIRException, IOException { try { - URL url = new URL(source+"?nocache=" + System.currentTimeMillis()); - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setRequestProperty("Accept", contentType); - return TextFile.streamToBytes(conn.getInputStream()); + try { + // try with cache-busting option and then try withhout in case the server doesn't support that + URL url = new URL(source+"?nocache=" + System.currentTimeMillis()); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setRequestProperty("Accept", contentType); + return TextFile.streamToBytes(conn.getInputStream()); + } catch (Exception e) { + URL url = new URL(source); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setRequestProperty("Accept", contentType); + return TextFile.streamToBytes(conn.getInputStream()); + } } catch (IOException e) { + if (errors != null) { + errors.add("Error accessing "+source+": "+e.getMessage()); + } if (optional) return null; else @@ -1123,7 +1157,8 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst } } - public void setQuestionnaires(List questionnaires) { + public void setQuestionnaireMode(Validator.QuestionnaireMode questionnaireMode) { + this.questionnaireMode = questionnaireMode; } public void setNative(boolean doNative) { @@ -1135,8 +1170,8 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst FhirFormat cntType = null; } - public Content loadContent(String source, String opName) throws FHIRException, IOException { - Map s = loadIgSource(source, false, false); + public Content loadContent(String source, String opName, boolean asIg) throws FHIRException, IOException { + Map s = loadIgSource(source, false, asIg); Content res = new Content(); if (s.size() != 1) throw new FHIRException("Unable to find resource " + source + " to "+opName); @@ -1192,7 +1227,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst InstanceValidator validator = getValidator(); for (String ref : refs) { - Content cnt = loadContent(ref, "validate"); + Content cnt = loadContent(ref, "validate", false); List messages = new ArrayList(); Element e = null; try { @@ -1264,7 +1299,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst List refs = new ArrayList(); handleSources(sources, refs); for (String ref : refs) { - Content cnt = loadContent(ref, "validate"); + Content cnt = loadContent(ref, "validate", false); String s = TextFile.bytesToString(cnt.focus); if (s.contains("http://hl7.org/fhir/3.0")) { versions.see("3.0", "Profile in "+ref); @@ -1293,7 +1328,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst TimeTracker.Session tts = context.clock().start("validation"); context.clock().milestone(); System.out.print(" Validate " + ref); - Content cnt = loadContent(ref, "validate"); + Content cnt = loadContent(ref, "validate", false); try { OperationOutcome outcome = validate(ref, cnt.focus, cnt.cntType, profiles); ToolingExtensions.addStringExtension(outcome, ToolingExtensions.EXT_OO_FILE, ref); @@ -1485,7 +1520,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst } public org.hl7.fhir.r5.elementmodel.Element transform(String source, String map) throws FHIRException, IOException { - Content cnt = loadContent(source, "validate"); + Content cnt = loadContent(source, "validate", false); return transform(cnt.focus, cnt.cntType, map); } @@ -1530,7 +1565,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst } public DomainResource generate(String source, String version) throws FHIRException, IOException, EOperationOutcome { - Content cnt = loadContent(source, "validate"); + Content cnt = loadContent(source, "validate", false); Resource res = loadResourceByVersion(version, cnt.focus, source); RenderingContext rc = new RenderingContext(context, null, null, "http://hl7.org/fhir", "", null, ResourceRendererMode.RESOURCE); RendererFactory.factory(res, rc).render((DomainResource) res); @@ -1538,20 +1573,20 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst } public void convert(String source, String output) throws FHIRException, IOException { - Content cnt = loadContent(source, "validate"); + Content cnt = loadContent(source, "validate", false); Element e = Manager.parse(context, new ByteArrayInputStream(cnt.focus), cnt.cntType); Manager.compose(context, e, new FileOutputStream(output), (output.endsWith(".json") ? FhirFormat.JSON : FhirFormat.XML), OutputStyle.PRETTY, null); } public String evaluateFhirPath(String source, String expression) throws FHIRException, IOException { - Content cnt = loadContent(source, "validate"); + Content cnt = loadContent(source, "validate", false); FHIRPathEngine fpe = new FHIRPathEngine(context); Element e = Manager.parse(context, new ByteArrayInputStream(cnt.focus), cnt.cntType); return fpe.evaluateToString(e, expression); } public StructureDefinition snapshot(String source, String version) throws FHIRException, IOException { - Content cnt = loadContent(source, "validate"); + Content cnt = loadContent(source, "validate", false); Resource res = loadResourceByVersion(version, cnt.focus, Utilities.getFileNameForName(source)); if (!(res instanceof StructureDefinition)) @@ -1595,6 +1630,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst validator.getImplementationGuides().addAll(igs); validator.getBundleValidationRules().addAll(bundleValidationRules); validator.getValidationControl().putAll(validationControl ); + validator.setQuestionnaireMode(questionnaireMode); return validator; } @@ -2054,7 +2090,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst } public byte[] transformVersion(String source, String targetVer, FhirFormat format, Boolean canDoNative) throws FHIRException, IOException, Exception { - Content cnt = loadContent(source, "validate"); + Content cnt = loadContent(source, "validate", false); org.hl7.fhir.r5.elementmodel.Element src = Manager.parse(context, new ByteArrayInputStream(cnt.focus), cnt.cntType); // if the src has a url, we try to use the java code diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/Validator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/Validator.java index 8b6a38bf3..be1da42f0 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/Validator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/Validator.java @@ -91,6 +91,8 @@ public class Validator { public enum EngineMode { VALIDATION, TRANSFORM, NARRATIVE, SNAPSHOT, SCAN, CONVERT, FHIRPATH, VERSION } + + public enum QuestionnaireMode { NONE, CHECK, REQUIRED } private static CliContext cliContext; 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 1ed9893a9..eea13ac6c 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 @@ -54,8 +54,9 @@ public class CliContext { @JsonProperty("igs") private List igs = new ArrayList(); - @JsonProperty("questionnaires") - private List questionnaires = new ArrayList(); + @JsonProperty("questionnaire") + private Validator.QuestionnaireMode questionnaireMode = Validator.QuestionnaireMode.CHECK; + @JsonProperty("profiles") private List profiles = new ArrayList(); @JsonProperty("sources") @@ -118,22 +119,14 @@ public class CliContext { return this; } - @JsonProperty("questionnaires") - public List getQuestionnaires() { - return questionnaires; + @JsonProperty("questionnaire") + public Validator.QuestionnaireMode getQuestionnaireMode() { + return questionnaireMode; } - @JsonProperty("questionnaires") - public CliContext setQuestionnaires(List questionnaires) { - this.questionnaires = questionnaires; - return this; - } - - public CliContext addQuestionnaire(String questionnaire) { - if (this.questionnaires == null) { - this.questionnaires = new ArrayList<>(); - } - this.questionnaires.add(questionnaire); + @JsonProperty("questionnaire") + public CliContext setQuestionnaireMode(Validator.QuestionnaireMode questionnaireMode) { + this.questionnaireMode = questionnaireMode; return this; } @@ -482,7 +475,7 @@ public class CliContext { Objects.equals(snomedCT, that.snomedCT) && Objects.equals(targetVer, that.targetVer) && Objects.equals(igs, that.igs) && - Objects.equals(questionnaires, that.questionnaires) && + Objects.equals(questionnaireMode, that.questionnaireMode) && Objects.equals(profiles, that.profiles) && Objects.equals(sources, that.sources) && Objects.equals(crumbTrails, that.crumbTrails) && @@ -494,6 +487,6 @@ public class CliContext { @Override public int hashCode() { - return Objects.hash(doNative, anyExtensionsAllowed, hintAboutNonMustSupport, recursive, doDebug, assumeValidRestReferences, canDoNative, noInternalCaching, noExtensibleBindingMessages, map, output, txServer, sv, txLog, mapLog, lang, fhirpath, snomedCT, targetVer, igs, questionnaires, profiles, sources, mode, locale, locations, crumbTrails, showTimes); + return Objects.hash(doNative, anyExtensionsAllowed, hintAboutNonMustSupport, recursive, doDebug, assumeValidRestReferences, canDoNative, noInternalCaching, noExtensibleBindingMessages, map, output, txServer, sv, txLog, mapLog, lang, fhirpath, snomedCT, targetVer, igs, questionnaireMode, profiles, sources, mode, locale, locations, crumbTrails, showTimes); } } \ No newline at end of file diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/services/StandAloneValidatorFetcher.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/services/StandAloneValidatorFetcher.java index 9626987e7..0dd0b3412 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/services/StandAloneValidatorFetcher.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/services/StandAloneValidatorFetcher.java @@ -14,9 +14,9 @@ import org.hl7.fhir.r5.utils.IResourceValidator.ReferenceValidationPolicy; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.VersionUtilities; import org.hl7.fhir.utilities.VersionUtilities.VersionURLInfo; -import org.hl7.fhir.utilities.cache.BasePackageCacheManager; -import org.hl7.fhir.utilities.cache.FilesystemPackageCacheManager; -import org.hl7.fhir.utilities.cache.NpmPackage; +import org.hl7.fhir.utilities.npm.BasePackageCacheManager; +import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; +import org.hl7.fhir.utilities.npm.NpmPackage; import org.hl7.fhir.validation.cli.services.StandAloneValidatorFetcher.IPackageInstaller; public class StandAloneValidatorFetcher implements IValidatorResourceFetcher { 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 5ec8f9b56..0b8580e40 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 @@ -203,7 +203,7 @@ public class ValidationService { validator.loadIg(src, cliContext.isRecursive()); } System.out.print(" Get set... "); - validator.setQuestionnaires(cliContext.getQuestionnaires()); + validator.setQuestionnaireMode(cliContext.getQuestionnaireMode()); validator.setNative(cliContext.isDoNative()); validator.setHintAboutNonMustSupport(cliContext.isHintAboutNonMustSupport()); validator.setAnyExtensionsAllowed(cliContext.isAnyExtensionsAllowed()); diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/utils/Display.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/utils/Display.java index a57040513..09397e776 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/utils/Display.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/utils/Display.java @@ -2,8 +2,8 @@ package org.hl7.fhir.validation.cli.utils; import org.hl7.fhir.r5.model.Constants; import org.hl7.fhir.utilities.VersionUtilities; -import org.hl7.fhir.utilities.cache.FilesystemPackageCacheManager; -import org.hl7.fhir.utilities.cache.ToolsVersion; +import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; +import org.hl7.fhir.utilities.npm.ToolsVersion; import java.io.IOException; 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 68638cdfc..20211de73 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 @@ -122,8 +122,10 @@ public class Params { } else if (args[i].equals(QUESTIONNAIRE)) { if (i + 1 == args.length) throw new Error("Specified -questionnaire without indicating questionnaire file"); - else - cliContext.addQuestionnaire(args[++i]); + else { + String q = args[++i]; + cliContext.setQuestionnaireMode(Validator.QuestionnaireMode.valueOf(q)); + } } else if (args[i].equals(NATIVE)) { cliContext.setDoNative(true); } else if (args[i].equals(ASSUME_VALID_REST_REF)) { 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 0c7ab8330..4794d133a 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 @@ -140,6 +140,7 @@ import org.hl7.fhir.r5.utils.ToolingExtensions; import org.hl7.fhir.r5.utils.XVerExtensionManager; import org.hl7.fhir.utilities.i18n.I18nConstants; import org.hl7.fhir.validation.BaseValidator; +import org.hl7.fhir.validation.Validator.QuestionnaireMode; import org.hl7.fhir.validation.instance.type.BundleValidator; import org.hl7.fhir.validation.instance.type.CodeSystemValidator; import org.hl7.fhir.validation.instance.type.MeasureValidator; @@ -375,6 +376,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat private boolean crumbTrails; private List bundleValidationRules = new ArrayList<>(); private boolean validateValueSetCodesOnTxServer = true; + private QuestionnaireMode questionnaireMode; public InstanceValidator(IWorkerContext theContext, IEvaluationContext hostServices) { super(theContext); @@ -3844,9 +3846,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } else if (element.getType().equals("Observation")) { validateObservation(errors, element, stack); } else if (element.getType().equals("Questionnaire")) { - new QuestionnaireValidator(context, myEnableWhenEvaluator, fpe, timeTracker).validateQuestionannaire(errors, element, element, stack); + new QuestionnaireValidator(context, myEnableWhenEvaluator, fpe, timeTracker, questionnaireMode).validateQuestionannaire(errors, element, element, stack); } else if (element.getType().equals("QuestionnaireResponse")) { - new QuestionnaireValidator(context, myEnableWhenEvaluator, fpe, timeTracker).validateQuestionannaireResponse(hostContext, errors, element, stack); + new QuestionnaireValidator(context, myEnableWhenEvaluator, fpe, timeTracker, questionnaireMode).validateQuestionannaireResponse(hostContext, errors, element, stack); } else if (element.getType().equals("Measure")) { new MeasureValidator(context, timeTracker).validateMeasure(hostContext, errors, element, stack); } else if (element.getType().equals("MeasureReport")) { @@ -5081,4 +5083,12 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } + public void setQuestionnaireMode(QuestionnaireMode questionnaireMode) { + this.questionnaireMode = questionnaireMode; + } + + public QuestionnaireMode getQuestionnaireMode() { + return questionnaireMode; + } + } \ No newline at end of file diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/QuestionnaireValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/QuestionnaireValidator.java index 492a689af..d37ffa2a1 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/QuestionnaireValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/QuestionnaireValidator.java @@ -45,6 +45,7 @@ import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType; import org.hl7.fhir.utilities.validation.ValidationMessage.Source; import org.hl7.fhir.validation.BaseValidator; import org.hl7.fhir.validation.TimeTracker; +import org.hl7.fhir.validation.Validator.QuestionnaireMode; import org.hl7.fhir.validation.instance.EnableWhenEvaluator; import org.hl7.fhir.validation.instance.EnableWhenEvaluator.QStack; import org.hl7.fhir.validation.instance.utils.NodeStack; @@ -56,13 +57,15 @@ public class QuestionnaireValidator extends BaseValidator { private EnableWhenEvaluator myEnableWhenEvaluator; private FHIRPathEngine fpe; + private QuestionnaireMode questionnaireMode; - public QuestionnaireValidator(IWorkerContext context, EnableWhenEvaluator myEnableWhenEvaluator, FHIRPathEngine fpe, TimeTracker timeTracker) { + public QuestionnaireValidator(IWorkerContext context, EnableWhenEvaluator myEnableWhenEvaluator, FHIRPathEngine fpe, TimeTracker timeTracker, QuestionnaireMode questionnaireMode) { super(context); source = Source.InstanceValidator; this.myEnableWhenEvaluator = myEnableWhenEvaluator; this.fpe = fpe; this.timeTracker = timeTracker; + this.questionnaireMode = questionnaireMode; } public void validateQuestionannaire(List errors, Element element, Element element2, NodeStack stack) { @@ -164,6 +167,9 @@ public class QuestionnaireValidator extends BaseValidator { } public void validateQuestionannaireResponse(ValidatorHostContext hostContext, List errors, Element element, NodeStack stack) throws FHIRException { + if (questionnaireMode == QuestionnaireMode.NONE) { + return; + } Element q = element.getNamedChild("questionnaire"); String questionnaire = null; if (q != null) { @@ -179,9 +185,15 @@ public class QuestionnaireValidator extends BaseValidator { questionnaire = q.getChildValue("reference"); } } - if (hint(errors, IssueType.REQUIRED, element.line(), element.col(), stack.getLiteralPath(), questionnaire != null, I18nConstants.QUESTIONNAIRE_QR_Q_NONE)) { + boolean ok = questionnaireMode == QuestionnaireMode.REQUIRED ? + rule(errors, IssueType.REQUIRED, element.line(), element.col(), stack.getLiteralPath(), questionnaire != null, I18nConstants.QUESTIONNAIRE_QR_Q_NONE) : + hint(errors, IssueType.REQUIRED, element.line(), element.col(), stack.getLiteralPath(), questionnaire != null, I18nConstants.QUESTIONNAIRE_QR_Q_NONE); + if (ok) { Questionnaire qsrc = questionnaire.startsWith("#") ? loadQuestionnaire(element, questionnaire.substring(1)) : context.fetchResource(Questionnaire.class, questionnaire); - if (warning(errors, IssueType.REQUIRED, q.line(), q.col(), stack.getLiteralPath(), qsrc != null, I18nConstants.QUESTIONNAIRE_QR_Q_NOTFOUND, questionnaire)) { + ok = questionnaireMode == QuestionnaireMode.REQUIRED ? + rule(errors, IssueType.REQUIRED, q.line(), q.col(), stack.getLiteralPath(), qsrc != null, I18nConstants.QUESTIONNAIRE_QR_Q_NOTFOUND, questionnaire) : + warning(errors, IssueType.REQUIRED, q.line(), q.col(), stack.getLiteralPath(), qsrc != null, I18nConstants.QUESTIONNAIRE_QR_Q_NOTFOUND, questionnaire); + if (ok) { boolean inProgress = "in-progress".equals(element.getNamedChildValue("status")); validateQuestionannaireResponseItems(hostContext, qsrc, qsrc.getItem(), errors, element, stack, inProgress, element, new QStack(qsrc, element)); } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ValueSetValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ValueSetValidator.java index a10173f81..b3d4c0e3c 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ValueSetValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ValueSetValidator.java @@ -56,28 +56,28 @@ public class ValueSetValidator extends BaseValidator { List composes = vs.getChildrenByName("compose"); int cc = 0; for (Element compose : composes) { - validateValueSetCompose(errors, compose, stack.push(compose, cc, null, null), vs.getNamedChildValue("url")); + validateValueSetCompose(errors, compose, stack.push(compose, cc, null, null), vs.getNamedChildValue("url"), "retired".equals(vs.getNamedChildValue("url"))); cc++; } } } - private void validateValueSetCompose(List errors, Element compose, NodeStack stack, String vsid) { + private void validateValueSetCompose(List errors, Element compose, NodeStack stack, String vsid, boolean retired) { List includes = compose.getChildrenByName("include"); int ci = 0; for (Element include : includes) { - validateValueSetInclude(errors, include, stack.push(include, ci, null, null), vsid); + validateValueSetInclude(errors, include, stack.push(include, ci, null, null), vsid, retired); ci++; } List excludes = compose.getChildrenByName("exclude"); int ce = 0; for (Element exclude : excludes) { - validateValueSetInclude(errors, exclude, stack.push(exclude, ce, null, null), vsid); + validateValueSetInclude(errors, exclude, stack.push(exclude, ce, null, null), vsid, retired); ce++; } } - private void validateValueSetInclude(List errors, Element include, NodeStack stack, String vsid) { + private void validateValueSetInclude(List errors, Element include, NodeStack stack, String vsid, boolean retired) { String system = include.getChildValue("system"); String version = include.getChildValue("version"); List valuesets = include.getChildrenByName("valueSet"); @@ -125,9 +125,9 @@ public class ValueSetValidator extends BaseValidator { } for (VSCodingValidationRequest cv : batch) { if (version == null) { - warning(errors, IssueType.BUSINESSRULE, cv.getStack().getLiteralPath(), cv.getResult().isOk(), I18nConstants.VALUESET_INCLUDE_INVALID_CONCEPT_CODE, system, cv.getCoding().getCode()); + warningOrHint(errors, IssueType.BUSINESSRULE, cv.getStack().getLiteralPath(), cv.getResult().isOk(), !retired, I18nConstants.VALUESET_INCLUDE_INVALID_CONCEPT_CODE, system, cv.getCoding().getCode()); } else { - warning(errors, IssueType.BUSINESSRULE, cv.getStack().getLiteralPath(), cv.getResult().isOk(), I18nConstants.VALUESET_INCLUDE_INVALID_CONCEPT_CODE_VER, system, version, cv.getCoding().getCode()); + warningOrHint(errors, IssueType.BUSINESSRULE, cv.getStack().getLiteralPath(), cv.getResult().isOk(), !retired, I18nConstants.VALUESET_INCLUDE_INVALID_CONCEPT_CODE_VER, system, version, cv.getCoding().getCode()); } } } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/packages/PackageValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/packages/PackageValidator.java index 099f203c8..6304f71d4 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/packages/PackageValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/packages/PackageValidator.java @@ -7,11 +7,11 @@ import java.util.List; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRFormatError; import org.hl7.fhir.utilities.VersionUtilities; -import org.hl7.fhir.utilities.cache.NpmPackage; -import org.hl7.fhir.utilities.cache.FilesystemPackageCacheManager; -import org.hl7.fhir.utilities.cache.CachingPackageClient; -import org.hl7.fhir.utilities.cache.PackageClient.PackageInfo; -import org.hl7.fhir.utilities.cache.ToolsVersion; +import org.hl7.fhir.utilities.npm.CachingPackageClient; +import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; +import org.hl7.fhir.utilities.npm.NpmPackage; +import org.hl7.fhir.utilities.npm.ToolsVersion; +import org.hl7.fhir.utilities.npm.PackageClient.PackageInfo; public class PackageValidator { diff --git a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/comparison/tests/ComparisonTests.java b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/comparison/tests/ComparisonTests.java index 367977e38..d0cdf5425 100644 --- a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/comparison/tests/ComparisonTests.java +++ b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/comparison/tests/ComparisonTests.java @@ -38,9 +38,9 @@ import org.hl7.fhir.r5.test.utils.TestingUtilities; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.VersionUtilities; -import org.hl7.fhir.utilities.cache.NpmPackage; -import org.hl7.fhir.utilities.cache.FilesystemPackageCacheManager; -import org.hl7.fhir.utilities.cache.ToolsVersion; +import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; +import org.hl7.fhir.utilities.npm.NpmPackage; +import org.hl7.fhir.utilities.npm.ToolsVersion; import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity; import org.hl7.fhir.utilities.xhtml.XhtmlComposer; diff --git a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/conversion/tests/R3R4ConversionTests.java b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/conversion/tests/R3R4ConversionTests.java index 03a5ba941..ba1bcce23 100644 --- a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/conversion/tests/R3R4ConversionTests.java +++ b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/conversion/tests/R3R4ConversionTests.java @@ -22,8 +22,8 @@ import org.hl7.fhir.r4.utils.StructureMapUtilities.ITransformerServices; import org.hl7.fhir.utilities.IniFile; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; -import org.hl7.fhir.utilities.cache.FilesystemPackageCacheManager; -import org.hl7.fhir.utilities.cache.ToolsVersion; +import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; +import org.hl7.fhir.utilities.npm.ToolsVersion; import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity; import org.junit.jupiter.api.Disabled; diff --git a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/conversion/tests/UtilitiesXTests.java b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/conversion/tests/UtilitiesXTests.java index 0cb9c8016..1e65b8cb7 100644 --- a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/conversion/tests/UtilitiesXTests.java +++ b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/conversion/tests/UtilitiesXTests.java @@ -59,9 +59,8 @@ import org.hl7.fhir.utilities.CSFile; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.VersionUtilities; -import org.hl7.fhir.utilities.cache.FilesystemPackageCacheManager; -import org.hl7.fhir.utilities.cache.ToolsVersion; - +import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; +import org.hl7.fhir.utilities.npm.ToolsVersion; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; diff --git a/pom.xml b/pom.xml index 5829bbfe7..219d4e271 100644 --- a/pom.xml +++ b/pom.xml @@ -19,7 +19,7 @@ 5.1.0 - 1.1.44 + 1.1.45-SNAPSHOT 5.6.2 3.0.0-M4 0.8.5 From 2e8953a81db72c48526048366685069ef7b514fb Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Thu, 1 Oct 2020 11:00:31 +1000 Subject: [PATCH 66/73] add search on IG registry to PackageClient --- .../npm/FilesystemPackageCacheManager.java | 29 ------------- .../hl7/fhir/utilities/npm/PackageClient.java | 43 +++++++++++++++++++ .../tests/CachingPackageClientTests.java | 8 ++++ 3 files changed, 51 insertions(+), 29 deletions(-) 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 66f22cc17..985065479 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 @@ -911,33 +911,4 @@ public class FilesystemPackageCacheManager extends BasePackageCacheManager imple return false; } - - - -//public List getUrls() throws IOException { -// if (allUrls == null) -// { -// IniFile ini = new IniFile(Utilities.path(cacheFolder, "packages.ini")); -// allUrls = new ArrayList<>(); -// for (String s : ini.getPropertyNames("urls")) -// allUrls.add(ini.getStringProperty("urls", s)); -// try { -// URL url = new URL("https://raw.githubusercontent.com/FHIR/ig-registry/master/fhir-ig-list.json?nocache=" + System.currentTimeMillis()); -// HttpURLConnection connection = (HttpURLConnection) url.openConnection(); -// connection.setRequestMethod("GET"); -// InputStream json = connection.getInputStream(); -// JsonObject packages = (JsonObject) new com.google.gson.JsonParser().parse(TextFile.streamToString(json)); -// JsonArray guides = packages.getAsJsonArray("guides"); -// for (JsonElement g : guides) { -// JsonObject gi = (JsonObject) g; -// if (gi.has("canonical")) -// if (!allUrls.contains(gi.get("canonical").getAsString())) -// allUrls.add(gi.get("canonical").getAsString()); -// } -// } catch (Exception e) { -// System.out.println("Listing known Implementation Guides failed: "+e.getMessage()); -// } -// } -// return allUrls; -//} } \ No newline at end of file diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageClient.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageClient.java index 18f9e434f..3fdaa7e35 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageClient.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageClient.java @@ -8,6 +8,7 @@ import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.VersionUtilities; import org.hl7.fhir.utilities.json.JSONUtil; +import org.hl7.fhir.utilities.json.JsonTrackingParser; import java.io.File; import java.io.FileInputStream; @@ -223,4 +224,46 @@ public class PackageClient { } } + + public List listFromRegistry(String name, String canonical, String fhirVersion) throws IOException { + List result = new ArrayList<>(); + JsonObject packages = JsonTrackingParser.fetchJson("https://raw.githubusercontent.com/FHIR/ig-registry/master/fhir-ig-list.json?nocache=" + System.currentTimeMillis()); + for (JsonObject o : JSONUtil.objects(packages, "guides")) { + if (o.has("canonical")) { + String id = JSONUtil.str(o, "npm-name"); + String pname = JSONUtil.str(o, "name"); + String pcanonical = JSONUtil.str(o, "canonical"); + String description = JSONUtil.str(o, "description"); + boolean ok = true; + if (ok && !Utilities.noString(name)) { + ok = (pname != null && pname.contains(name)) || (description != null && description.contains(name)) || (id != null && id.contains(name)); + } + if (ok && !Utilities.noString(canonical)) { + ok = pcanonical.contains(canonical); + } + String version = null; + String fVersion = null; + String url = null; + + if (ok) { + // if we can find something... + for (JsonObject e : JSONUtil.objects(o, "editions")) { + if (fhirVersion == null || fhirVersion.equals(JSONUtil.str(e, "fhir-version"))) { + String v = JSONUtil.str(e, "ig-version"); + if (version == null || VersionUtilities.isThisOrLater(version, v)) { + version = v; + fVersion = e.getAsJsonArray("fhir-version").get(0).getAsString(); + url = JSONUtil.str(e, "url"); + } + } + } + } + if (version != null) { + result.add(new PackageInfo(id, version, fVersion, description, url, pcanonical)); + } + } + } + return result; + } + } \ No newline at end of file diff --git a/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/tests/CachingPackageClientTests.java b/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/tests/CachingPackageClientTests.java index a9d592118..3ba3e61e3 100644 --- a/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/tests/CachingPackageClientTests.java +++ b/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/tests/CachingPackageClientTests.java @@ -104,4 +104,12 @@ public class CachingPackageClientTests { List matches = client.getVersions("Simplifier.Core.STU3X"); Assertions.assertTrue(matches.size() == 0); } + + @Test + public void testRegistry() throws IOException { + CachingPackageClient client = new CachingPackageClient("http://packages.fhir.org/packages"); + List matches1 = client.listFromRegistry(null, null, null); + List matches2 = client.listFromRegistry(null, null, "4.0.1"); + Assertions.assertTrue(matches1.size() > matches2.size()); + } } \ No newline at end of file From 77d33e8afaf413e6c337fbbc63d257dacaed8e97 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Thu, 1 Oct 2020 11:04:34 +1000 Subject: [PATCH 67/73] Fix comment parsing and add focus to FHIRPath function extensions --- .../java/org/hl7/fhir/r4/utils/FHIRLexer.java | 49 ++++++---- .../org/hl7/fhir/r4/utils/FHIRPathEngine.java | 4 +- .../org/hl7/fhir/r4/utils/LiquidEngine.java | 4 +- .../fhir/r4/utils/StructureMapUtilities.java | 2 +- .../org/hl7/fhir/r4/test/FHIRPathTests.java | 2 +- .../fhir/r4/test/SnapShotGenerationTests.java | 2 +- .../r5/comparison/ComparisonRenderer.java | 2 +- .../java/org/hl7/fhir/r5/utils/FHIRLexer.java | 92 +++++++++++++------ .../org/hl7/fhir/r5/utils/FHIRPathEngine.java | 4 +- .../org/hl7/fhir/r5/utils/LiquidEngine.java | 4 +- .../fhir/r5/utils/StructureMapUtilities.java | 58 +++--------- .../org/hl7/fhir/r5/test/FHIRPathTests.java | 2 +- .../fhir/r5/test/SnapShotGenerationTests.java | 2 +- .../hl7/fhir/utilities/SourceLocation.java | 19 ++++ .../instance/InstanceValidator.java | 2 +- .../tests/SnapShotGenerationXTests.java | 2 +- .../validation/tests/ValidationTests.java | 2 +- 17 files changed, 143 insertions(+), 109 deletions(-) diff --git a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/FHIRLexer.java b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/FHIRLexer.java index 83619c66b..671fc4021 100644 --- a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/FHIRLexer.java +++ b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/FHIRLexer.java @@ -146,23 +146,8 @@ public class FHIRLexer { } public void next() throws FHIRLexerException { + skipWhitespaceAndComments(); current = null; - boolean last13 = false; - while (cursor < source.length() && Character.isWhitespace(source.charAt(cursor))) { - if (source.charAt(cursor) == '\r') { - currentLocation.setLine(currentLocation.getLine() + 1); - currentLocation.setColumn(1); - last13 = true; - } else if (!last13 && (source.charAt(cursor) == '\n')) { - currentLocation.setLine(currentLocation.getLine() + 1); - currentLocation.setColumn(1); - last13 = false; - } else { - last13 = false; - currentLocation.setColumn(currentLocation.getColumn() + 1); - } - cursor++; - } currentStart = cursor; currentStartLocation = currentLocation; if (cursor < source.length()) { @@ -208,9 +193,8 @@ public class FHIRLexer { } else if (ch == '/') { cursor++; if (cursor < source.length() && (source.charAt(cursor) == '/')) { - cursor++; - while (cursor < source.length() && !((source.charAt(cursor) == '\r') || source.charAt(cursor) == '\n')) - cursor++; + // this is en error - should already have been skipped + error("This shoudn't happen?"); } current = source.substring(currentStart, cursor); } else if (ch == '$') { @@ -297,6 +281,33 @@ public class FHIRLexer { } + private void skipWhitespaceAndComments() { + boolean last13 = false; + boolean done = false; + while (cursor < source.length() && !done) { + if (cursor < source.length() -1 && "//".equals(source.substring(cursor, cursor+2))) { + while (cursor < source.length() && !((source.charAt(cursor) == '\r') || source.charAt(cursor) == '\n')) + cursor++; + } else if (cursor < source.length() - 1 && "/*".equals(source.substring(cursor, cursor+2))) { + while (cursor < source.length() - 1 && !"*/".equals(source.substring(cursor, cursor+2))) { + last13 = currentLocation.checkChar(source.charAt(cursor), last13); + cursor++; + } + if (cursor >= source.length() -1) { + error("Unfinished comment"); + } else { + cursor = cursor + 2; + } + } else if (Character.isWhitespace(source.charAt(cursor))) { + last13 = currentLocation.checkChar(source.charAt(cursor), last13); + cursor++; + } else { + done = true; + } + } + } + + private boolean isDateChar(char ch,int start) { int eot = source.charAt(start+1) == 'T' ? 10 : 20; diff --git a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/FHIRPathEngine.java b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/FHIRPathEngine.java index 7bc7ec1c0..31701df2f 100644 --- a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/FHIRPathEngine.java +++ b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/FHIRPathEngine.java @@ -233,7 +233,7 @@ public class FHIRPathEngine { * @param parameters * @return */ - public List executeFunction(Object appContext, String functionName, List> parameters); + public List executeFunction(Object appContext, List focus, String functionName, List> parameters); /** * Implementation of resolve() function. Passed a string, return matching resource, if one is known - else null @@ -2858,7 +2858,7 @@ public class FHIRPathEngine { List> params = new ArrayList>(); for (ExpressionNode p : exp.getParameters()) params.add(execute(context, focus, p, true)); - return hostServices.executeFunction(context.appInfo, exp.getName(), params); + return hostServices.executeFunction(context.appInfo, focus, exp.getName(), params); } default: throw new Error("not Implemented yet"); diff --git a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/LiquidEngine.java b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/LiquidEngine.java index 008d857eb..6a307b8ca 100644 --- a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/LiquidEngine.java +++ b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/LiquidEngine.java @@ -405,11 +405,11 @@ public class LiquidEngine implements IEvaluationContext { } @Override - public List executeFunction(Object appContext, String functionName, List> parameters) { + public List executeFunction(Object appContext, List focus, String functionName, List> parameters) { if (externalHostServices == null) return null; LiquidEngineContext ctxt = (LiquidEngineContext) appContext; - return externalHostServices.executeFunction(ctxt.externalContext, functionName, parameters); + return externalHostServices.executeFunction(ctxt.externalContext, focus, functionName, parameters); } @Override diff --git a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/StructureMapUtilities.java b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/StructureMapUtilities.java index a38603abe..ae4524927 100644 --- a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/StructureMapUtilities.java +++ b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/StructureMapUtilities.java @@ -202,7 +202,7 @@ public class StructureMapUtilities { } @Override - public List executeFunction(Object appContext, String functionName, List> parameters) { + public List executeFunction(Object appContext, List focus, String functionName, List> parameters) { throw new Error("Not Implemented Yet"); } diff --git a/org.hl7.fhir.r4/src/test/java/org/hl7/fhir/r4/test/FHIRPathTests.java b/org.hl7.fhir.r4/src/test/java/org/hl7/fhir/r4/test/FHIRPathTests.java index 79ea4fcb0..357f8e143 100644 --- a/org.hl7.fhir.r4/src/test/java/org/hl7/fhir/r4/test/FHIRPathTests.java +++ b/org.hl7.fhir.r4/src/test/java/org/hl7/fhir/r4/test/FHIRPathTests.java @@ -64,7 +64,7 @@ public class FHIRPathTests { } @Override - public List executeFunction(Object appContext, String functionName, List> parameters) { + public List executeFunction(Object appContext, List focus, String functionName, List> parameters) { throw new NotImplementedException("Not done yet (FHIRPathTestEvaluationServices.executeFunction), when item is element"); } diff --git a/org.hl7.fhir.r4/src/test/java/org/hl7/fhir/r4/test/SnapShotGenerationTests.java b/org.hl7.fhir.r4/src/test/java/org/hl7/fhir/r4/test/SnapShotGenerationTests.java index caef44031..747c66149 100644 --- a/org.hl7.fhir.r4/src/test/java/org/hl7/fhir/r4/test/SnapShotGenerationTests.java +++ b/org.hl7.fhir.r4/src/test/java/org/hl7/fhir/r4/test/SnapShotGenerationTests.java @@ -316,7 +316,7 @@ public class SnapShotGenerationTests { } @Override - public List executeFunction(Object appContext, String functionName, List> parameters) { + public List executeFunction(Object appContext, List focus, String functionName, List> parameters) { if ("fixture".equals(functionName)) { String id = fp.convertToString(parameters.get(0)); Resource res = fetchFixture(id); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/ComparisonRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/ComparisonRenderer.java index ceb3a3f75..43d18b3d2 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/ComparisonRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/ComparisonRenderer.java @@ -242,7 +242,7 @@ public class ComparisonRenderer implements IEvaluationContext { } @Override - public List executeFunction(Object appContext, String functionName, List> parameters) { + public List executeFunction(Object appContext, List focus, String functionName, List> parameters) { return null; } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRLexer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRLexer.java index 4400bcdc8..be10c5ba2 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRLexer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRLexer.java @@ -1,5 +1,10 @@ package org.hl7.fhir.r5.utils; +import java.util.ArrayList; +import java.util.List; +import java.util.StringJoiner; + +import org.apache.poi.xssf.model.Comments; import org.hl7.fhir.exceptions.FHIRException; /* @@ -34,6 +39,7 @@ import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.r5.model.ExpressionNode; +import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; import org.hl7.fhir.utilities.SourceLocation; import org.hl7.fhir.utilities.Utilities; @@ -65,6 +71,7 @@ public class FHIRLexer { private int cursor; private int currentStart; private String current; + private List comments = new ArrayList<>(); private SourceLocation currentLocation; private SourceLocation currentStartLocation; private int id; @@ -146,23 +153,8 @@ public class FHIRLexer { } public void next() throws FHIRLexerException { + skipWhitespaceAndComments(); current = null; - boolean last13 = false; - while (cursor < source.length() && Character.isWhitespace(source.charAt(cursor))) { - if (source.charAt(cursor) == '\r') { - currentLocation.setLine(currentLocation.getLine() + 1); - currentLocation.setColumn(1); - last13 = true; - } else if (!last13 && (source.charAt(cursor) == '\n')) { - currentLocation.setLine(currentLocation.getLine() + 1); - currentLocation.setColumn(1); - last13 = false; - } else { - last13 = false; - currentLocation.setColumn(currentLocation.getColumn() + 1); - } - cursor++; - } currentStart = cursor; currentStartLocation = currentLocation; if (cursor < source.length()) { @@ -208,9 +200,8 @@ public class FHIRLexer { } else if (ch == '/') { cursor++; if (cursor < source.length() && (source.charAt(cursor) == '/')) { - cursor++; - while (cursor < source.length() && !((source.charAt(cursor) == '\r') || source.charAt(cursor) == '\n')) - cursor++; + // this is en error - should already have been skipped + error("This shoudn't happen?"); } current = source.substring(currentStart, cursor); } else if (ch == '$') { @@ -296,7 +287,38 @@ public class FHIRLexer { } } - + private void skipWhitespaceAndComments() { + comments.clear(); + boolean last13 = false; + boolean done = false; + while (cursor < source.length() && !done) { + if (cursor < source.length() -1 && "//".equals(source.substring(cursor, cursor+2))) { + int start = cursor+2; + while (cursor < source.length() && !((source.charAt(cursor) == '\r') || source.charAt(cursor) == '\n')) { + cursor++; + } + comments.add(source.substring(start, cursor).trim()); + } else if (cursor < source.length() - 1 && "/*".equals(source.substring(cursor, cursor+2))) { + int start = cursor+2; + while (cursor < source.length() - 1 && !"*/".equals(source.substring(cursor, cursor+2))) { + last13 = currentLocation.checkChar(source.charAt(cursor), last13); + cursor++; + } + if (cursor >= source.length() -1) { + error("Unfinished comment"); + } else { + comments.add(source.substring(start, cursor).trim()); + cursor = cursor + 2; + } + } else if (Character.isWhitespace(source.charAt(cursor))) { + last13 = currentLocation.checkChar(source.charAt(cursor), last13); + cursor++; + } else { + done = true; + } + } + } + private boolean isDateChar(char ch,int start) { int eot = source.charAt(start+1) == 'T' ? 10 : 20; @@ -321,9 +343,31 @@ public class FHIRLexer { this.current = current; } - public boolean hasComment() { - return !done() && current.startsWith("//"); + public boolean hasComments() { + return comments.size() > 0; } + + public List getComments() { + return comments; + } + + public String getAllComments() { + CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder("\r\n"); + b.addAll(comments); + comments.clear(); + return b.toString(); + } + + public String getFirstComment() { + if (hasComments()) { + String s = comments.get(0); + comments.remove(0); + return s; + } else { + return null; + } + } + public boolean hasToken(String kw) { return !done() && kw.equals(current); } @@ -472,10 +516,6 @@ public class FHIRLexer { return b.toString(); } - void skipComments() throws FHIRLexerException { - while (!done() && hasComment()) - next(); - } public int getCurrentStart() { return currentStart; } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java index 334b8648f..8edc8e9d4 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java @@ -285,7 +285,7 @@ public class FHIRPathEngine { * @param parameters * @return */ - public List executeFunction(Object appContext, String functionName, List> parameters); + public List executeFunction(Object appContext, List focus, String functionName, List> parameters); /** * Implementation of resolve() function. Passed a string, return matching resource, if one is known - else null @@ -3463,7 +3463,7 @@ public class FHIRPathEngine { for (ExpressionNode p : exp.getParameters()) { params.add(execute(context, focus, p, true)); } - return hostServices.executeFunction(context.appInfo, exp.getName(), params); + return hostServices.executeFunction(context.appInfo, focus, exp.getName(), params); } default: throw new Error("not Implemented yet"); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/LiquidEngine.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/LiquidEngine.java index 31100c7bf..03dcc8b1f 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/LiquidEngine.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/LiquidEngine.java @@ -632,11 +632,11 @@ public class LiquidEngine implements IEvaluationContext { } @Override - public List executeFunction(Object appContext, String functionName, List> parameters) { + public List executeFunction(Object appContext, List focus, String functionName, List> parameters) { if (externalHostServices == null) return null; LiquidEngineContext ctxt = (LiquidEngineContext) appContext; - return externalHostServices.executeFunction(ctxt.externalContext, functionName, parameters); + return externalHostServices.executeFunction(ctxt.externalContext, focus, functionName, parameters); } @Override diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/StructureMapUtilities.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/StructureMapUtilities.java index 83442379c..41040413d 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/StructureMapUtilities.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/StructureMapUtilities.java @@ -202,7 +202,7 @@ public class StructureMapUtilities { } @Override - public List executeFunction(Object appContext, String functionName, List> parameters) { + public List executeFunction(Object appContext, List focus, String functionName, List> parameters) { throw new Error("Not Implemented Yet"); } @@ -748,15 +748,12 @@ public class StructureMapUtilities { FHIRLexer lexer = new FHIRLexer(text, srcName); if (lexer.done()) throw lexer.error("Map Input cannot be empty"); - lexer.skipComments(); lexer.token("map"); StructureMap result = new StructureMap(); result.setUrl(lexer.readConstant("url")); lexer.token("="); result.setName(lexer.readConstant("name")); - if (lexer.hasComment()) { - result.setDescription(getMultiLineComments(lexer)); - } + result.setDescription(lexer.getAllComments()); while (lexer.hasToken("conceptmap")) parseConceptMap(result, lexer); @@ -782,7 +779,6 @@ public class StructureMapUtilities { map.setStatus(PublicationStatus.DRAFT); // todo: how to add this to the text format result.getContained().add(map); lexer.token("{"); - lexer.skipComments(); // lexer.token("source"); // map.setSource(new UriType(lexer.readConstant("source"))); // lexer.token("target"); @@ -824,25 +820,11 @@ public class StructureMapUtilities { tgt.setCode(lexer.take()); if (tgt.getCode().startsWith("\"")) tgt.setCode(lexer.processConstant(tgt.getCode())); - if (lexer.hasComment()) - tgt.setComment(lexer.take().substring(2).trim()); + tgt.setComment(lexer.getFirstComment()); } lexer.token("}"); } - private String getMultiLineComments(FHIRLexer lexer) { - String comment = null; - while (lexer.hasComment()) { - String newComment = lexer.take().substring(2).trim(); - if (comment == null) { - comment = newComment; - } else { - comment += "\r\n"+newComment; - } - } - return comment; - } - private ConceptMapGroupComponent getGroup(ConceptMap map, String srcs, String tgts) { for (ConceptMapGroupComponent grp : map.getGroup()) { if (grp.getSource().equals(srcs)) @@ -895,9 +877,7 @@ public class StructureMapUtilities { lexer.token("as"); st.setMode(StructureMapModelMode.fromCode(lexer.take())); lexer.skipToken(";"); - if (lexer.hasComment() && currentLine == lexer.getCurrentLocation().getLine()) { - st.setDocumentation(lexer.take().substring(2).trim()); - } + st.setDocumentation(lexer.getFirstComment()); } private void parseImports(StructureMap result, FHIRLexer lexer) throws FHIRException { @@ -905,19 +885,11 @@ public class StructureMapUtilities { int currentLine = lexer.getCurrentLocation().getLine(); result.addImport(lexer.readConstant("url")); lexer.skipToken(";"); - if (lexer.hasComment() && currentLine == lexer.getCurrentLocation().getLine()) { - lexer.next(); - } + lexer.getFirstComment(); } private void parseGroup(StructureMap result, FHIRLexer lexer) throws FHIRException { - String comment = null; - if (lexer.hasComment()) { - comment = getMultiLineComments(lexer); - if (lexer.done()) { - return ; - } - } + String comment = lexer.getAllComments(); lexer.token("group"); StructureMapGroupComponent group = result.addGroup(); if (comment != null) { @@ -975,7 +947,6 @@ public class StructureMapUtilities { parseRule(result, group.getRule(), lexer, true); } } else { - lexer.skipComments(); while (lexer.hasToken("input")) parseInput(group, lexer, false); while (!lexer.hasToken("endgroup")) { @@ -1003,11 +974,8 @@ public class StructureMapUtilities { if (!newFmt) { lexer.token("as"); input.setMode(StructureMapInputMode.fromCode(lexer.take())); - if (lexer.hasComment()) { - input.setDocumentation(lexer.take().substring(2).trim()); - } + input.setDocumentation(lexer.getFirstComment()); lexer.skipToken(";"); - lexer.skipComments(); } } @@ -1018,12 +986,7 @@ public class StructureMapUtilities { lexer.token(":"); lexer.token("for"); } else { - if (lexer.hasComment()) { - rule.setDocumentation(this.getMultiLineComments(lexer)); - if (lexer.hasToken("}")) { - return ; // catched a comment at the end - } - } + rule.setDocumentation(lexer.getFirstComment()); } list.add(rule); boolean done = false; @@ -1062,8 +1025,9 @@ public class StructureMapUtilities { lexer.next(); } } - } else if (lexer.hasComment()) { - rule.setDocumentation(getMultiLineComments(lexer)); + } + if (!rule.hasDocumentation() && lexer.hasComments()) { + rule.setDocumentation(lexer.getFirstComment()); } if (isSimpleSyntax(rule)) { rule.getSourceFirstRep().setVariable(AUTO_VAR_NAME); diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/FHIRPathTests.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/FHIRPathTests.java index 22b3e3e21..e1518e4ef 100644 --- a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/FHIRPathTests.java +++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/FHIRPathTests.java @@ -72,7 +72,7 @@ public class FHIRPathTests { } @Override - public List executeFunction(Object appContext, String functionName, List> parameters) { + public List executeFunction(Object appContext, List focus, String functionName, List> parameters) { throw new NotImplementedException("Not done yet (FHIRPathTestEvaluationServices.executeFunction), when item is element"); } diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/SnapShotGenerationTests.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/SnapShotGenerationTests.java index d18e7dff1..135934e47 100644 --- a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/SnapShotGenerationTests.java +++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/SnapShotGenerationTests.java @@ -380,7 +380,7 @@ public class SnapShotGenerationTests { } @Override - public List executeFunction(Object appContext, String functionName, List> parameters) { + public List executeFunction(Object appContext, List focus, String functionName, List> parameters) { if ("fixture".equals(functionName)) { String id = fp.convertToString(parameters.get(0)); Resource res = fetchFixture(id); diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/SourceLocation.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/SourceLocation.java index 5ed864765..93c15dacb 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/SourceLocation.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/SourceLocation.java @@ -24,4 +24,23 @@ public class SourceLocation { public String toString() { return Integer.toString(line)+", "+Integer.toString(column); } + + public void newLine() { + setLine(getLine() + 1); + setColumn(1); + } + public boolean checkChar(char ch, boolean last13) { + if (ch == '\r') { + newLine(); + return true; + } else if (ch == '\n') { + if (!last13) { + newLine(); + } + return false; + } else { + setColumn(getColumn() + 1); + return false; + } + } } 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 4794d133a..e42434539 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 @@ -226,7 +226,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } @Override - public List executeFunction(Object appContext, String functionName, List> parameters) { + public List executeFunction(Object appContext, List focus, String functionName, List> parameters) { throw new Error(context.formatMessage(I18nConstants.NOT_DONE_YET_VALIDATORHOSTSERVICESEXECUTEFUNCTION)); } diff --git a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/conversion/tests/SnapShotGenerationXTests.java b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/conversion/tests/SnapShotGenerationXTests.java index 030352c40..8b616af25 100644 --- a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/conversion/tests/SnapShotGenerationXTests.java +++ b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/conversion/tests/SnapShotGenerationXTests.java @@ -334,7 +334,7 @@ public class SnapShotGenerationXTests { } @Override - public List executeFunction(Object appContext, String functionName, List> parameters) { + public List executeFunction(Object appContext, List focus, String functionName, List> parameters) { if ("fixture".equals(functionName)) { String id = fp.convertToString(parameters.get(0)); Resource res = fetchFixture(id); 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 7dc58c52c..7c8671c66 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 @@ -435,7 +435,7 @@ public class ValidationTests implements IEvaluationContext, IValidatorResourceFe } @Override - public List executeFunction(Object appContext, String functionName, List> parameters) { + public List executeFunction(Object appContext, List focus, String functionName, List> parameters) { return null; } From 3e6863ef70e21413c04a61de6c8d2d49cd048b4f Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Thu, 1 Oct 2020 11:05:24 +1000 Subject: [PATCH 68/73] Support for additional checking in IG Publisher --- RELEASE_NOTES.md | 5 ++++- .../java/org/hl7/fhir/r5/utils/NPMPackageGenerator.java | 6 ++++++ .../hl7/fhir/utilities/CommaSeparatedStringBuilder.java | 9 +++++++++ .../org/hl7/fhir/utilities/json/JsonTrackingParser.java | 9 +++++++++ 4 files changed, 28 insertions(+), 1 deletion(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index e97786dae..d773df519 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,7 +1,10 @@ Validator: -* Add date addition/subtraction to FHIRPath +* Add date addition/subtraction to FHIRPath + add parsing comments * Fix questionnaire mode parameter support for validator * add extra debugging when valdiator can't fetch content to validate Other code changes: * rename org.hl7.fhir.utilities.cache to org.hl7.fhir.utilities.npm +* report error locations for run time FHIRPath errors +* add search on IG registry to PackageClient +* add focus to FHIRPath function extensions \ No newline at end of file diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/NPMPackageGenerator.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/NPMPackageGenerator.java index 5a8d2fb93..3bbfe0ed3 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/NPMPackageGenerator.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/NPMPackageGenerator.java @@ -102,6 +102,7 @@ public class NPMPackageGenerator { private JsonObject packageJ; private JsonObject packageManifest; private NpmPackageIndexBuilder indexer; + private String igVersion; public NPMPackageGenerator(String destFile, String canonical, String url, PackageType kind, ImplementationGuide ig, Date date, boolean notForPublication) throws FHIRException, IOException { @@ -184,6 +185,7 @@ public class NPMPackageGenerator { JsonObject npm = new JsonObject(); npm.addProperty("name", ig.getPackageId()); npm.addProperty("version", ig.getVersion()); + igVersion = ig.getVersion(); npm.addProperty("tools-version", ToolsVersion.TOOLS_VERSION); npm.addProperty("type", kind.getCode()); npm.addProperty("date", dt); @@ -395,5 +397,9 @@ public class NPMPackageGenerator { } } + public String version() { + return igVersion; + } + } \ No newline at end of file diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/CommaSeparatedStringBuilder.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/CommaSeparatedStringBuilder.java index 3973f1506..89c2eec92 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/CommaSeparatedStringBuilder.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/CommaSeparatedStringBuilder.java @@ -1,5 +1,7 @@ package org.hl7.fhir.utilities; +import java.util.List; + /* Copyright (c) 2011+, HL7, Inc. All rights reserved. @@ -76,4 +78,11 @@ public class CommaSeparatedStringBuilder { append(s); } + + public void addAll(List list) { + for (String s : list) { + append(s); + } + + } } \ No newline at end of file diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/json/JsonTrackingParser.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/json/JsonTrackingParser.java index e133d2f02..977d6873b 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/json/JsonTrackingParser.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/json/JsonTrackingParser.java @@ -36,6 +36,8 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; import java.math.BigDecimal; +import java.net.HttpURLConnection; +import java.net.URL; import java.util.Map; import java.util.Stack; @@ -671,6 +673,13 @@ public class JsonTrackingParser { Gson gson = new GsonBuilder().setPrettyPrinting().create(); return gson.toJson(json); } + + public static JsonObject fetchJson(String source) throws IOException { + URL url = new URL(source+"?nocache=" + System.currentTimeMillis()); + HttpURLConnection c = (HttpURLConnection) url.openConnection(); + c.setInstanceFollowRedirects(true); + return parseJson(c.getInputStream()); + } } \ No newline at end of file From e89da42514b379815b3162c422fc7681377297cb Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Thu, 1 Oct 2020 12:39:10 +1000 Subject: [PATCH 69/73] * fix error setting up mapping log * fix rendering of definitions in CodeSystems * fix error rendering bundles in bundles --- RELEASE_NOTES.md | 5 ++++- .../hl7/fhir/r5/renderers/BundleRenderer.java | 4 +++- .../fhir/r5/renderers/RendererFactory.java | 3 +++ .../fhir/r5/renderers/ValueSetRenderer.java | 22 +++++++++++-------- .../hl7/fhir/validation/ValidationEngine.java | 4 +++- 5 files changed, 26 insertions(+), 12 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index d773df519..5d6f544b9 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -2,9 +2,12 @@ Validator: * Add date addition/subtraction to FHIRPath + add parsing comments * Fix questionnaire mode parameter support for validator * add extra debugging when valdiator can't fetch content to validate +* fix error setting up mapping log Other code changes: * rename org.hl7.fhir.utilities.cache to org.hl7.fhir.utilities.npm * report error locations for run time FHIRPath errors * add search on IG registry to PackageClient -* add focus to FHIRPath function extensions \ No newline at end of file +* add focus to FHIRPath function extensions +* fix rendering of definitions in CodeSystems +* fix error rendering bundles in bundles diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/BundleRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/BundleRenderer.java index 735b139dd..1817f6994 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/BundleRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/BundleRenderer.java @@ -43,7 +43,9 @@ public class BundleRenderer extends ResourceRenderer { @Override public boolean render(XhtmlNode x, Resource r) throws FHIRFormatError, DefinitionException, IOException, FHIRException, EOperationOutcome { - return render(x, (Bundle) r); + XhtmlNode n = render((Bundle) r); + x.addChildren(n.getChildNodes()); + return false; } @Override diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/RendererFactory.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/RendererFactory.java index f435b97a1..fef306984 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/RendererFactory.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/RendererFactory.java @@ -78,6 +78,9 @@ public class RendererFactory { if ("Parameters".equals(resourceName)) { return new ParametersRenderer(context); } + if ("Bundle".equals(resourceName)) { + return new BundleRenderer(context); + } return new ProfileDrivenRenderer(context); } 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 94ff7037f..cb0919b01 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 @@ -829,7 +829,8 @@ public class ValueSetRenderer extends TerminologyRenderer { boolean hasDefinition = false; for (ConceptReferenceComponent c : inc.getConcept()) { hasComments = hasComments || ExtensionHelper.hasExtension(c, ToolingExtensions.EXT_VS_COMMENT); - hasDefinition = hasDefinition || ExtensionHelper.hasExtension(c, ToolingExtensions.EXT_DEFINITION); + ConceptDefinitionComponent cc = definitions.get(c.getCode()); + hasDefinition = hasDefinition || ((cc != null && cc.hasDefinition()) || ExtensionHelper.hasExtension(c, ToolingExtensions.EXT_DEFINITION)); } if (hasComments || hasDefinition) hasExtensions = true; @@ -846,16 +847,19 @@ public class ValueSetRenderer extends TerminologyRenderer { else if (cc != null && !Utilities.noString(cc.getDisplay())) td.addText(cc.getDisplay()); - if (ExtensionHelper.hasExtension(c, ToolingExtensions.EXT_DEFINITION)) { + if (hasDefinition) { td = tr.td(); - smartAddText(td, ToolingExtensions.readStringExtension(c, ToolingExtensions.EXT_DEFINITION)); - } else if (cc != null && !Utilities.noString(cc.getDefinition())) { - td = tr.td(); - smartAddText(td, cc.getDefinition()); + if (ExtensionHelper.hasExtension(c, ToolingExtensions.EXT_DEFINITION)) { + smartAddText(td, ToolingExtensions.readStringExtension(c, ToolingExtensions.EXT_DEFINITION)); + } else if (cc != null && !Utilities.noString(cc.getDefinition())) { + smartAddText(td, cc.getDefinition()); + } } - - if (ExtensionHelper.hasExtension(c, ToolingExtensions.EXT_VS_COMMENT)) { - smartAddText(tr.td(), "Note: "+ToolingExtensions.readStringExtension(c, ToolingExtensions.EXT_VS_COMMENT)); + if (hasComments) { + td = tr.td(); + if (ExtensionHelper.hasExtension(c, ToolingExtensions.EXT_VS_COMMENT)) { + smartAddText(td, "Note: "+ToolingExtensions.readStringExtension(c, ToolingExtensions.EXT_VS_COMMENT)); + } } if (doLangs) { addLangaugesToRow(c, langs, tr); 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 506c54680..596055d66 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 @@ -1635,7 +1635,9 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst } public void setMapLog(String mapLog) throws FileNotFoundException { - this.mapLog = new PrintWriter(mapLog); + if (mapLog != null) { + this.mapLog = new PrintWriter(mapLog); + } } public void prepare() { From 073e59a964aaf3b2487ce8b9d3472b7c385f89b2 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Thu, 1 Oct 2020 13:02:05 +1000 Subject: [PATCH 70/73] update test case dependency --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 219d4e271..3bf94146a 100644 --- a/pom.xml +++ b/pom.xml @@ -19,7 +19,7 @@ 5.1.0 - 1.1.45-SNAPSHOT + 1.1.45 5.6.2 3.0.0-M4 0.8.5 From ea0b4c0c1c1097cf59da770b53f7ba8456b2252d Mon Sep 17 00:00:00 2001 From: markiantorno Date: Thu, 1 Oct 2020 04:12:17 +0000 Subject: [PATCH 71/73] Release: v5.1.16 Validator: * Add date addition/subtraction to FHIRPath + add parsing comments * Fix questionnaire mode parameter support for validator * add extra debugging when valdiator can't fetch content to validate * fix error setting up mapping log Other code changes: * rename org.hl7.fhir.utilities.cache to org.hl7.fhir.utilities.npm * report error locations for run time FHIRPath errors * add search on IG registry to PackageClient * add focus to FHIRPath function extensions * fix rendering of definitions in CodeSystems * fix error rendering bundles in bundles ***NO_CI*** --- org.hl7.fhir.convertors/pom.xml | 2 +- org.hl7.fhir.dstu2/pom.xml | 2 +- org.hl7.fhir.dstu2016may/pom.xml | 2 +- org.hl7.fhir.dstu3/pom.xml | 2 +- org.hl7.fhir.r4/pom.xml | 2 +- org.hl7.fhir.r5/pom.xml | 2 +- org.hl7.fhir.report/pom.xml | 2 +- org.hl7.fhir.utilities/pom.xml | 2 +- org.hl7.fhir.validation.cli/pom.xml | 2 +- org.hl7.fhir.validation/pom.xml | 2 +- pom.xml | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/org.hl7.fhir.convertors/pom.xml b/org.hl7.fhir.convertors/pom.xml index efecd1e44..c8b37f213 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 - 5.1.16-SNAPSHOT + 5.1.16 ../pom.xml diff --git a/org.hl7.fhir.dstu2/pom.xml b/org.hl7.fhir.dstu2/pom.xml index fb0ee362b..fa6c713bb 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 - 5.1.16-SNAPSHOT + 5.1.16 ../pom.xml diff --git a/org.hl7.fhir.dstu2016may/pom.xml b/org.hl7.fhir.dstu2016may/pom.xml index ab92b63cc..d5dcb1b19 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 - 5.1.16-SNAPSHOT + 5.1.16 ../pom.xml diff --git a/org.hl7.fhir.dstu3/pom.xml b/org.hl7.fhir.dstu3/pom.xml index 731ae419f..867d130c9 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 - 5.1.16-SNAPSHOT + 5.1.16 ../pom.xml diff --git a/org.hl7.fhir.r4/pom.xml b/org.hl7.fhir.r4/pom.xml index d1b6c2663..39e5b23b6 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 - 5.1.16-SNAPSHOT + 5.1.16 ../pom.xml diff --git a/org.hl7.fhir.r5/pom.xml b/org.hl7.fhir.r5/pom.xml index bf27f4d2e..eab0d9cc0 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 - 5.1.16-SNAPSHOT + 5.1.16 ../pom.xml diff --git a/org.hl7.fhir.report/pom.xml b/org.hl7.fhir.report/pom.xml index 1573279dc..5dcffc51d 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 - 5.1.16-SNAPSHOT + 5.1.16 ../pom.xml diff --git a/org.hl7.fhir.utilities/pom.xml b/org.hl7.fhir.utilities/pom.xml index 8072b4156..873cbb8ad 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 - 5.1.16-SNAPSHOT + 5.1.16 ../pom.xml diff --git a/org.hl7.fhir.validation.cli/pom.xml b/org.hl7.fhir.validation.cli/pom.xml index e1ec66572..4fc2a9a5f 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 - 5.1.16-SNAPSHOT + 5.1.16 ../pom.xml diff --git a/org.hl7.fhir.validation/pom.xml b/org.hl7.fhir.validation/pom.xml index ee22814c6..3e693deb4 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 - 5.1.16-SNAPSHOT + 5.1.16 ../pom.xml diff --git a/pom.xml b/pom.xml index 3bf94146a..7a2c2ccd8 100644 --- a/pom.xml +++ b/pom.xml @@ -14,7 +14,7 @@ HAPI FHIR. --> org.hl7.fhir.core - 5.1.16-SNAPSHOT + 5.1.16 pom From 1f583d6ba7974c168b01da96dc0dc729702ce05c Mon Sep 17 00:00:00 2001 From: markiantorno Date: Thu, 1 Oct 2020 04:37:43 +0000 Subject: [PATCH 72/73] Updating version to: 5.1.17-SNAPSHOT and incrementing test cases dependency. --- RELEASE_NOTES.md | 13 ------------- org.hl7.fhir.convertors/pom.xml | 2 +- org.hl7.fhir.dstu2/pom.xml | 2 +- org.hl7.fhir.dstu2016may/pom.xml | 2 +- org.hl7.fhir.dstu3/pom.xml | 2 +- org.hl7.fhir.r4/pom.xml | 2 +- org.hl7.fhir.r5/pom.xml | 2 +- org.hl7.fhir.report/pom.xml | 2 +- org.hl7.fhir.utilities/pom.xml | 2 +- org.hl7.fhir.validation.cli/pom.xml | 2 +- org.hl7.fhir.validation/pom.xml | 2 +- pom.xml | 2 +- 12 files changed, 11 insertions(+), 24 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 5d6f544b9..e69de29bb 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,13 +0,0 @@ -Validator: -* Add date addition/subtraction to FHIRPath + add parsing comments -* Fix questionnaire mode parameter support for validator -* add extra debugging when valdiator can't fetch content to validate -* fix error setting up mapping log - -Other code changes: -* rename org.hl7.fhir.utilities.cache to org.hl7.fhir.utilities.npm -* report error locations for run time FHIRPath errors -* add search on IG registry to PackageClient -* add focus to FHIRPath function extensions -* fix rendering of definitions in CodeSystems -* fix error rendering bundles in bundles diff --git a/org.hl7.fhir.convertors/pom.xml b/org.hl7.fhir.convertors/pom.xml index c8b37f213..f013169f6 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 - 5.1.16 + 5.1.17-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.dstu2/pom.xml b/org.hl7.fhir.dstu2/pom.xml index fa6c713bb..171a34fec 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 - 5.1.16 + 5.1.17-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.dstu2016may/pom.xml b/org.hl7.fhir.dstu2016may/pom.xml index d5dcb1b19..d40fdf29a 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 - 5.1.16 + 5.1.17-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.dstu3/pom.xml b/org.hl7.fhir.dstu3/pom.xml index 867d130c9..978a05efe 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 - 5.1.16 + 5.1.17-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.r4/pom.xml b/org.hl7.fhir.r4/pom.xml index 39e5b23b6..60bb2e702 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 - 5.1.16 + 5.1.17-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.r5/pom.xml b/org.hl7.fhir.r5/pom.xml index eab0d9cc0..3cc483033 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 - 5.1.16 + 5.1.17-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.report/pom.xml b/org.hl7.fhir.report/pom.xml index 5dcffc51d..ef4bb14a3 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 - 5.1.16 + 5.1.17-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.utilities/pom.xml b/org.hl7.fhir.utilities/pom.xml index 873cbb8ad..cbe28db37 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 - 5.1.16 + 5.1.17-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.validation.cli/pom.xml b/org.hl7.fhir.validation.cli/pom.xml index 4fc2a9a5f..a8dcf2676 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 - 5.1.16 + 5.1.17-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.validation/pom.xml b/org.hl7.fhir.validation/pom.xml index 3e693deb4..ffa5971b1 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 - 5.1.16 + 5.1.17-SNAPSHOT ../pom.xml diff --git a/pom.xml b/pom.xml index 7a2c2ccd8..8e975d598 100644 --- a/pom.xml +++ b/pom.xml @@ -14,7 +14,7 @@ HAPI FHIR. --> org.hl7.fhir.core - 5.1.16 + 5.1.17-SNAPSHOT pom From a8b715af9702412ad98633147d256785de6dc4b0 Mon Sep 17 00:00:00 2001 From: Itay Goren Date: Tue, 6 Oct 2020 19:07:57 +0300 Subject: [PATCH 73/73] fixed bug in conversion from dstu2 to r4 in timing resource --- .../convertors/VersionConvertor_10_40.java | 20 ++++++++++++------- .../resources/0_medication_request_40.json | 2 -- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/VersionConvertor_10_40.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/VersionConvertor_10_40.java index c9550402d..4db50132b 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/VersionConvertor_10_40.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/VersionConvertor_10_40.java @@ -2023,15 +2023,18 @@ public class VersionConvertor_10_40 { copyElement(src, tgt); if (src.hasBounds()) tgt.setBounds(convertType(src.getBounds())); - tgt.setCount(src.getCount()); + if (src.hasCount()) + tgt.setCount(src.getCount()); if (src.hasDurationElement()) tgt.setDurationElement(convertDecimal(src.getDurationElement())); if (src.hasDurationMaxElement()) tgt.setDurationMaxElement(convertDecimal(src.getDurationMaxElement())); if (src.hasDurationUnits()) tgt.setDurationUnitElement(convertUnitsOfTime(src.getDurationUnitsElement())); - tgt.setFrequency(src.getFrequency()); - tgt.setFrequencyMax(src.getFrequencyMax()); + if (src.hasFrequency()) + tgt.setFrequency(src.getFrequency()); + if (src.hasFrequencyMax()) + tgt.setFrequencyMax(src.getFrequencyMax()); if (src.hasPeriodElement()) tgt.setPeriodElement(convertDecimal(src.getPeriodElement())); if (src.hasPeriodMaxElement()) @@ -2051,15 +2054,18 @@ public class VersionConvertor_10_40 { copyElement(src, tgt); if (src.hasBounds()) tgt.setBounds(convertType(src.getBounds())); - tgt.setCount(src.getCount()); + if (src.hasCount()) + tgt.setCount(src.getCount()); if (src.hasDurationElement()) tgt.setDurationElement(convertDecimal(src.getDurationElement())); if (src.hasDurationMaxElement()) tgt.setDurationMaxElement(convertDecimal(src.getDurationMaxElement())); if (src.hasDurationUnit()) tgt.setDurationUnitsElement(convertUnitsOfTime(src.getDurationUnitElement())); - tgt.setFrequency(src.getFrequency()); - tgt.setFrequencyMax(src.getFrequencyMax()); + if (src.hasFrequency()) + tgt.setFrequency(src.getFrequency()); + if (src.hasFrequencyMax()) + tgt.setFrequencyMax(src.getFrequencyMax()); if (src.hasPeriodElement()) tgt.setPeriodElement(convertDecimal(src.getPeriodElement())); if (src.hasPeriodMaxElement()) @@ -3430,4 +3436,4 @@ public class VersionConvertor_10_40 { copyElement(src, tgt); return tgt; } -} \ No newline at end of file +} diff --git a/org.hl7.fhir.convertors/src/test/resources/0_medication_request_40.json b/org.hl7.fhir.convertors/src/test/resources/0_medication_request_40.json index 325b59a1a..a00906b3e 100644 --- a/org.hl7.fhir.convertors/src/test/resources/0_medication_request_40.json +++ b/org.hl7.fhir.convertors/src/test/resources/0_medication_request_40.json @@ -18,9 +18,7 @@ "dosageInstruction": [{"text": "Take 10 mg by mouth nightly.", "timing": {"repeat": {"boundsPeriod": {"start": "2016-11-15T00:00:00Z", "end": "2016-11-23T00:00:00Z"}, - "count": 0, "frequency": 1, - "frequencyMax": 0, "period": 1.0, "periodUnit": "d"}}, "asNeededBoolean": "False",