headers, byte[] body, long start) {
if (file == null)
return;
file.println("");
diff --git a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/model/Enumerations.java b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/model/Enumerations.java
index d2ce3d418..8da4196d8 100644
--- a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/model/Enumerations.java
+++ b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/model/Enumerations.java
@@ -1,6 +1,7 @@
package org.hl7.fhir.r4.model;
import org.hl7.fhir.exceptions.FHIRException;
+import org.hl7.fhir.utilities.Utilities;
public class Enumerations {
@@ -13173,1196 +13174,928 @@ public class Enumerations {
}
}
- public enum FHIRVersion {
- /**
- * Oldest archived version of FHIR.
- */
- _0_01,
- /**
- * 1st Draft for Comment (Sept 2012 Ballot).
- */
- _0_05,
- /**
- * 2nd Draft for Comment (January 2013 Ballot).
- */
- _0_06,
- /**
- * DSTU 1 Ballot version.
- */
- _0_11,
- /**
- * DSTU 1 version.
- */
- _0_0,
- /**
- * DSTU 1 Official version.
- */
- _0_0_80,
- /**
- * DSTU 1 Official version Technical Errata #1.
- */
- _0_0_81,
- /**
- * DSTU 1 Official version Technical Errata #2.
- */
- _0_0_82,
- /**
- * January 2015 Ballot.
- */
- _0_4,
- /**
- * Draft For Comment (January 2015 Ballot).
- */
- _0_4_0,
- /**
- * May 2015 Ballot.
- */
- _0_5,
- /**
- * DSTU 2 Ballot version (May 2015 Ballot).
- */
- _0_5_0,
- /**
- * DSTU 2 version.
- */
- _1_0,
- /**
- * DSTU 2 QA Preview + CQIF Ballot (Sep 2015).
- */
- _1_0_0,
- /**
- * DSTU 2 (Official version).
- */
- _1_0_1,
- /**
- * DSTU 2 (Official version) with 1 technical errata.
- */
- _1_0_2,
- /**
- * GAO Ballot version.
- */
- _1_1,
- /**
- * GAO Ballot + draft changes to main FHIR standard.
- */
- _1_1_0,
- /**
- * Connectathon 12 (Montreal) version.
- */
- _1_4,
- /**
- * CQF on FHIR Ballot + Connectathon 12 (Montreal).
- */
- _1_4_0,
- /**
- * Connectathon 13 (Baltimore) version.
- */
- _1_6,
- /**
- * FHIR STU3 Ballot + Connectathon 13 (Baltimore).
- */
- _1_6_0,
- /**
- * Connectathon 14 (San Antonio) version.
- */
- _1_8,
- /**
- * FHIR STU3 Candidate + Connectathon 14 (San Antonio).
- */
- _1_8_0,
- /**
- * STU3 version.
- */
- _3_0,
- /**
- * FHIR Release 3 (STU).
- */
- _3_0_0,
- /**
- * FHIR Release 3 (STU) with 1 technical errata.
- */
- _3_0_1,
- /**
- * FHIR Release 3 (STU) with 2 technical errata.
- */
- _3_0_2,
- /**
- * R4 Ballot #1 version.
- */
- _3_3,
- /**
- * R4 Ballot #1 + Connectaton 18 (Cologne).
- */
- _3_3_0,
- /**
- * R4 Ballot #2 version.
- */
- _3_5,
- /**
- * R4 Ballot #2 + Connectathon 19 (Baltimore).
- */
- _3_5_0,
- /**
- * R4 version.
- */
- _4_0,
- /**
- * FHIR Release 4 (Normative + STU).
- */
- _4_0_0,
- /**
- * FHIR Release 4 (Normative + STU) with 1 technical errata.
- */
- _4_0_1,
- /**
- * R4B Ballot #1 version.
- */
- _4_1,
- /**
- * R4B Ballot #1 + Connectathon 27 (Virtual).
- */
- _4_1_0, _4_3_0_SNAPSHOT1, _4_3_0_CIBUILD,
- /**
- * R5 Preview #1 version.
- */
- _4_2,
- /**
- * R5 Preview #1 + Connectathon 23 (Sydney).
- */
- _4_2_0,
- /**
- * R4B version.
- */
- _4_3,
- /**
- * FHIR Release 4B (Normative + STU).
- */
- _4_3_0,
- /**
- * R5 Preview #2 version.
- */
- _4_4,
- /**
- * R5 Preview #2 + Connectathon 24 (Virtual).
- */
- _4_4_0,
- /**
- * R5 Preview #3 version.
- */
- _4_5,
- /**
- * R5 Preview #3 + Connectathon 25 (Virtual).
- */
- _4_5_0,
- /**
- * R5 Draft Ballot version.
- */
- _4_6,
- /**
- * R5 Draft Ballot + Connectathon 27 (Virtual).
- */
- _4_6_0,
- /**
- * R5 Versions.
- */
- _5_0,
- /**
- * R5 Final Version.
- */
- _5_0_0,
- /**
- * R5 Rolling ci-build.
- */
- _5_0_0CIBUILD,
- /**
- * R5 Preview #2.
- */
- _5_0_0SNAPSHOT1,
- /**
- * R5 Interim tooling stage.
- */
- _5_0_0SNAPSHOT2,
- /**
- * R5 Ballot.
- */
- _5_0_0BALLOT,
- /**
- * R5Connectathon 32 release.
- */
- _5_0_0SNAPSHOT3, _5_0_0DRAFTFINAL,
- /**
- * added to help the parsers
- */
- NULL;
-
- public static FHIRVersion fromCode(String codeString) throws FHIRException {
- if (codeString == null || "".equals(codeString))
- return null;
- if ("0.01".equals(codeString))
- return _0_01;
- if ("0.05".equals(codeString))
- return _0_05;
- if ("0.06".equals(codeString))
- return _0_06;
- if ("0.11".equals(codeString))
- return _0_11;
- if ("0.0".equals(codeString))
- return _0_0;
- if ("0.0.80".equals(codeString))
- return _0_0_80;
- if ("0.0.81".equals(codeString))
- return _0_0_81;
- if ("0.0.82".equals(codeString))
- return _0_0_82;
- if ("0.4".equals(codeString))
- return _0_4;
- if ("0.4.0".equals(codeString))
- return _0_4_0;
- if ("0.5".equals(codeString))
- return _0_5;
- if ("0.5.0".equals(codeString))
- return _0_5_0;
- if ("1.0".equals(codeString))
- return _1_0;
- if ("1.0.0".equals(codeString))
- return _1_0_0;
- if ("1.0.1".equals(codeString))
- return _1_0_1;
- if ("1.0.2".equals(codeString))
- return _1_0_2;
- if ("1.1".equals(codeString))
- return _1_1;
- if ("1.1.0".equals(codeString))
- return _1_1_0;
- if ("1.4".equals(codeString))
- return _1_4;
- if ("1.4.0".equals(codeString))
- return _1_4_0;
- if ("1.6".equals(codeString))
- return _1_6;
- if ("1.6.0".equals(codeString))
- return _1_6_0;
- if ("1.8".equals(codeString))
- return _1_8;
- if ("1.8.0".equals(codeString))
- return _1_8_0;
- if ("3.0".equals(codeString))
- return _3_0;
- if ("3.0.0".equals(codeString))
- return _3_0_0;
- if ("3.0.1".equals(codeString))
- return _3_0_1;
- if ("3.0.2".equals(codeString))
- return _3_0_2;
- if ("3.3".equals(codeString))
- return _3_3;
- if ("3.3.0".equals(codeString))
- return _3_3_0;
- if ("3.5".equals(codeString))
- return _3_5;
- if ("3.5.0".equals(codeString))
- return _3_5_0;
- if ("4.0".equals(codeString))
- return _4_0;
- if ("4.0.0".equals(codeString))
- return _4_0_0;
- if ("4.0.1".equals(codeString))
- return _4_0_1;
- if ("4.1".equals(codeString))
- return _4_1;
- if ("4.1.0".equals(codeString))
- return _4_1_0;
- if ("4.3.0-snapshot1".equals(codeString))
- return _4_3_0_SNAPSHOT1;
- if ("4.3.0-cibuild".equals(codeString))
- return _4_3_0_CIBUILD;
- if ("4.2".equals(codeString))
- return _4_2;
- if ("4.2.0".equals(codeString))
- return _4_2_0;
- if ("4.3".equals(codeString))
- return _4_3;
- if ("4.3.0".equals(codeString))
- return _4_3_0;
- if ("4.4".equals(codeString))
- return _4_4;
- if ("4.4.0".equals(codeString))
- return _4_4_0;
- if ("4.5".equals(codeString))
- return _4_5;
- if ("4.5.0".equals(codeString))
- return _4_5_0;
- if ("4.6".equals(codeString))
- return _4_6;
- if ("4.6.0".equals(codeString))
- return _4_6_0;
- if ("5.0".equals(codeString))
- return _5_0;
- if ("5.0.0".equals(codeString))
- return _5_0_0;
- if ("5.0.0-cibuild".equals(codeString))
- return _5_0_0CIBUILD;
- if ("5.0.0-snapshot1".equals(codeString))
- return _5_0_0SNAPSHOT1;
- if ("5.0.0-snapshot2".equals(codeString))
- return _5_0_0SNAPSHOT2;
- if ("5.0.0-ballot".equals(codeString))
- return _5_0_0BALLOT;
- if ("5.0.0-snapshot3".equals(codeString))
- return _5_0_0SNAPSHOT3;
- if ("5.0.0-draft-final".equals(codeString))
- return _5_0_0DRAFTFINAL;
- throw new FHIRException("Unknown FHIRVersion code '" + codeString + "'");
+ public enum FHIRVersion {
+ /**
+ * Oldest archived version of FHIR.
+ */
+ _0_01,
+ /**
+ * 1st Draft for Comment (Sept 2012 Ballot).
+ */
+ _0_05,
+ /**
+ * 2nd Draft for Comment (January 2013 Ballot).
+ */
+ _0_06,
+ /**
+ * DSTU 1 Ballot version.
+ */
+ _0_11,
+ /**
+ * DSTU 1 version.
+ */
+ _0_0,
+ /**
+ * DSTU 1 Official version.
+ */
+ _0_0_80,
+ /**
+ * DSTU 1 Official version Technical Errata #1.
+ */
+ _0_0_81,
+ /**
+ * DSTU 1 Official version Technical Errata #2.
+ */
+ _0_0_82,
+ /**
+ * January 2015 Ballot.
+ */
+ _0_4,
+ /**
+ * Draft For Comment (January 2015 Ballot).
+ */
+ _0_4_0,
+ /**
+ * May 2015 Ballot.
+ */
+ _0_5,
+ /**
+ * DSTU 2 Ballot version (May 2015 Ballot).
+ */
+ _0_5_0,
+ /**
+ * DSTU 2 version.
+ */
+ _1_0,
+ /**
+ * DSTU 2 QA Preview + CQIF Ballot (Sep 2015).
+ */
+ _1_0_0,
+ /**
+ * DSTU 2 (Official version).
+ */
+ _1_0_1,
+ /**
+ * DSTU 2 (Official version) with 1 technical errata.
+ */
+ _1_0_2,
+ /**
+ * GAO Ballot version.
+ */
+ _1_1,
+ /**
+ * GAO Ballot + draft changes to main FHIR standard.
+ */
+ _1_1_0,
+ /**
+ * Connectathon 12 (Montreal) version.
+ */
+ _1_4,
+ /**
+ * CQF on FHIR Ballot + Connectathon 12 (Montreal).
+ */
+ _1_4_0,
+ /**
+ * Connectathon 13 (Baltimore) version.
+ */
+ _1_6,
+ /**
+ * FHIR STU3 Ballot + Connectathon 13 (Baltimore).
+ */
+ _1_6_0,
+ /**
+ * Connectathon 14 (San Antonio) version.
+ */
+ _1_8,
+ /**
+ * FHIR STU3 Candidate + Connectathon 14 (San Antonio).
+ */
+ _1_8_0,
+ /**
+ * STU3 version.
+ */
+ _3_0,
+ /**
+ * FHIR Release 3 (STU).
+ */
+ _3_0_0,
+ /**
+ * FHIR Release 3 (STU) with 1 technical errata.
+ */
+ _3_0_1,
+ /**
+ * FHIR Release 3 (STU) with 2 technical errata.
+ */
+ _3_0_2,
+ /**
+ * R4 Ballot #1 version.
+ */
+ _3_3,
+ /**
+ * R4 Ballot #1 + Connectaton 18 (Cologne).
+ */
+ _3_3_0,
+ /**
+ * R4 Ballot #2 version.
+ */
+ _3_5,
+ /**
+ * R4 Ballot #2 + Connectathon 19 (Baltimore).
+ */
+ _3_5_0,
+ /**
+ * R4 version.
+ */
+ _4_0,
+ /**
+ * FHIR Release 4 (Normative + STU).
+ */
+ _4_0_0,
+ /**
+ * FHIR Release 4 (Normative + STU) with 1 technical errata.
+ */
+ _4_0_1,
+ /**
+ * R4B Ballot #1 version.
+ */
+ _4_1,
+ /**
+ * R4B Ballot #1 + Connectathon 27 (Virtual).
+ */
+ _4_1_0,
+ /**
+ * R5 Preview #1 version.
+ */
+ _4_2,
+ /**
+ * R5 Preview #1 + Connectathon 23 (Sydney).
+ */
+ _4_2_0,
+ /**
+ * R4B version.
+ */
+ _4_3,
+ /**
+ * FHIR Release 4B (Normative + STU).
+ */
+ _4_3_0,
+ /**
+ * FHIR Release 4B CI-Builld.
+ */
+ _4_3_0CIBUILD,
+ /**
+ * FHIR Release 4B Snapshot #1.
+ */
+ _4_3_0SNAPSHOT1,
+ /**
+ * R5 Preview #2 version.
+ */
+ _4_4,
+ /**
+ * R5 Preview #2 + Connectathon 24 (Virtual).
+ */
+ _4_4_0,
+ /**
+ * R5 Preview #3 version.
+ */
+ _4_5,
+ /**
+ * R5 Preview #3 + Connectathon 25 (Virtual).
+ */
+ _4_5_0,
+ /**
+ * R5 Draft Ballot version.
+ */
+ _4_6,
+ /**
+ * R5 Draft Ballot + Connectathon 27 (Virtual).
+ */
+ _4_6_0,
+ /**
+ * R5 Versions.
+ */
+ _5_0,
+ /**
+ * R5 Final Version.
+ */
+ _5_0_0,
+ /**
+ * R5 Rolling ci-build.
+ */
+ _5_0_0CIBUILD,
+ /**
+ * R5 Preview #2.
+ */
+ _5_0_0SNAPSHOT1,
+ /**
+ * R5 Interim tooling stage.
+ */
+ _5_0_0SNAPSHOT2,
+ /**
+ * R5 Ballot.
+ */
+ _5_0_0BALLOT,
+ /**
+ * R5 January 2023 Staging Release + Connectathon 32.
+ */
+ _5_0_0SNAPSHOT3,
+ /**
+ * R5 Final QA.
+ */
+ _5_0_0DRAFTFINAL,
+ /**
+ * R6 Rolling ci-build.
+ */
+ _6_0_0CIBUILD,
+ /**
+ * R6 Formal version (does not exist yet)
+ */
+ _6_0_0,
+ _6_0_0_BALLOT1,
+ _6_0_0_BALLOT2,
+ /**
+ * added to help the parsers
+ */
+ NULL;
+ public static FHIRVersion fromCode(String codeString) throws FHIRException {
+ if (codeString == null || "".equals(codeString))
+ return null;
+ if ("0.01".equals(codeString))
+ return _0_01;
+ if ("0.05".equals(codeString))
+ return _0_05;
+ if ("0.06".equals(codeString))
+ return _0_06;
+ if ("0.11".equals(codeString))
+ return _0_11;
+ if ("0.0".equals(codeString))
+ return _0_0;
+ if ("0.0.80".equals(codeString))
+ return _0_0_80;
+ if ("0.0.81".equals(codeString))
+ return _0_0_81;
+ if ("0.0.82".equals(codeString))
+ return _0_0_82;
+ if ("0.4".equals(codeString))
+ return _0_4;
+ if ("0.4.0".equals(codeString))
+ return _0_4_0;
+ if ("0.5".equals(codeString))
+ return _0_5;
+ if ("0.5.0".equals(codeString))
+ return _0_5_0;
+ if ("1.0".equals(codeString))
+ return _1_0;
+ if ("1.0.0".equals(codeString))
+ return _1_0_0;
+ if ("1.0.1".equals(codeString))
+ return _1_0_1;
+ if ("1.0.2".equals(codeString))
+ return _1_0_2;
+ if ("1.1".equals(codeString))
+ return _1_1;
+ if ("1.1.0".equals(codeString))
+ return _1_1_0;
+ if ("1.4".equals(codeString))
+ return _1_4;
+ if ("1.4.0".equals(codeString))
+ return _1_4_0;
+ if ("1.6".equals(codeString))
+ return _1_6;
+ if ("1.6.0".equals(codeString))
+ return _1_6_0;
+ if ("1.8".equals(codeString))
+ return _1_8;
+ if ("1.8.0".equals(codeString))
+ return _1_8_0;
+ if ("3.0".equals(codeString))
+ return _3_0;
+ if ("3.0.0".equals(codeString))
+ return _3_0_0;
+ if ("3.0.1".equals(codeString))
+ return _3_0_1;
+ if ("3.0.2".equals(codeString))
+ return _3_0_2;
+ if ("3.3".equals(codeString))
+ return _3_3;
+ if ("3.3.0".equals(codeString))
+ return _3_3_0;
+ if ("3.5".equals(codeString))
+ return _3_5;
+ if ("3.5.0".equals(codeString))
+ return _3_5_0;
+ if ("4.0".equals(codeString))
+ return _4_0;
+ if ("4.0.0".equals(codeString))
+ return _4_0_0;
+ if ("4.0.1".equals(codeString))
+ return _4_0_1;
+ if ("4.1".equals(codeString))
+ return _4_1;
+ if ("4.1.0".equals(codeString))
+ return _4_1_0;
+ if ("4.2".equals(codeString))
+ return _4_2;
+ if ("4.2.0".equals(codeString))
+ return _4_2_0;
+ if ("4.3".equals(codeString))
+ return _4_3;
+ if ("4.3.0".equals(codeString))
+ return _4_3_0;
+ if ("4.3.0-cibuild".equals(codeString))
+ return _4_3_0CIBUILD;
+ if ("4.3.0-snapshot1".equals(codeString))
+ return _4_3_0SNAPSHOT1;
+ if ("4.4".equals(codeString))
+ return _4_4;
+ if ("4.4.0".equals(codeString))
+ return _4_4_0;
+ if ("4.5".equals(codeString))
+ return _4_5;
+ if ("4.5.0".equals(codeString))
+ return _4_5_0;
+ if ("4.6".equals(codeString))
+ return _4_6;
+ if ("4.6.0".equals(codeString))
+ return _4_6_0;
+ if ("5.0".equals(codeString))
+ return _5_0;
+ if ("5.0.0".equals(codeString))
+ return _5_0_0;
+ if ("5.0.0-cibuild".equals(codeString))
+ return _5_0_0CIBUILD;
+ if ("5.0.0-snapshot1".equals(codeString))
+ return _5_0_0SNAPSHOT1;
+ if ("5.0.0-snapshot2".equals(codeString))
+ return _5_0_0SNAPSHOT2;
+ if ("5.0.0-ballot".equals(codeString))
+ return _5_0_0BALLOT;
+ if ("5.0.0-snapshot3".equals(codeString))
+ return _5_0_0SNAPSHOT3;
+ if ("5.0.0-draft-final".equals(codeString))
+ return _5_0_0DRAFTFINAL;
+ if ("6.0.0-cibuild".equals(codeString))
+ return _6_0_0CIBUILD;
+ if ("6.0.0".equals(codeString))
+ return _6_0_0;
+ if ("6.0.0-ballot1".equals(codeString))
+ return _6_0_0_BALLOT1;
+ if ("6.0.0-ballot2".equals(codeString))
+ return _6_0_0_BALLOT2;
+ throw new FHIRException("Unknown FHIRVersion code '"+codeString+"'");
+ }
+ public static boolean isValidCode(String codeString) {
+ if (codeString == null || "".equals(codeString))
+ return false;
+ return Utilities.existsInList(codeString, "0.01", "0.05", "0.06", "0.11", "0.0", "0.0.80", "0.0.81", "0.0.82", "0.4", "0.4.0", "0.5", "0.5.0", "1.0", "1.0.0", "1.0.1", "1.0.2", "1.1", "1.1.0", "1.4", "1.4.0", "1.6", "1.6.0", "1.8", "1.8.0", "3.0", "3.0.0", "3.0.1", "3.0.2", "3.3", "3.3.0", "3.5", "3.5.0", "4.0", "4.0.0", "4.0.1", "4.1", "4.1.0", "4.2", "4.2.0", "4.3", "4.3.0", "4.3.0-cibuild", "4.3.0-snapshot1", "4.4", "4.4.0", "4.5", "4.5.0", "4.6", "4.6.0", "5.0", "5.0.0", "5.0.0-cibuild", "5.0.0-snapshot1", "5.0.0-snapshot2", "5.0.0-ballot", "5.0.0-snapshot3", "5.0.0-draft-final");
+ }
+ public String toCode() {
+ switch (this) {
+ case _0_01: return "0.01";
+ case _0_05: return "0.05";
+ case _0_06: return "0.06";
+ case _0_11: return "0.11";
+ case _0_0: return "0.0";
+ case _0_0_80: return "0.0.80";
+ case _0_0_81: return "0.0.81";
+ case _0_0_82: return "0.0.82";
+ case _0_4: return "0.4";
+ case _0_4_0: return "0.4.0";
+ case _0_5: return "0.5";
+ case _0_5_0: return "0.5.0";
+ case _1_0: return "1.0";
+ case _1_0_0: return "1.0.0";
+ case _1_0_1: return "1.0.1";
+ case _1_0_2: return "1.0.2";
+ case _1_1: return "1.1";
+ case _1_1_0: return "1.1.0";
+ case _1_4: return "1.4";
+ case _1_4_0: return "1.4.0";
+ case _1_6: return "1.6";
+ case _1_6_0: return "1.6.0";
+ case _1_8: return "1.8";
+ case _1_8_0: return "1.8.0";
+ case _3_0: return "3.0";
+ case _3_0_0: return "3.0.0";
+ case _3_0_1: return "3.0.1";
+ case _3_0_2: return "3.0.2";
+ case _3_3: return "3.3";
+ case _3_3_0: return "3.3.0";
+ case _3_5: return "3.5";
+ case _3_5_0: return "3.5.0";
+ case _4_0: return "4.0";
+ case _4_0_0: return "4.0.0";
+ case _4_0_1: return "4.0.1";
+ case _4_1: return "4.1";
+ case _4_1_0: return "4.1.0";
+ case _4_2: return "4.2";
+ case _4_2_0: return "4.2.0";
+ case _4_3: return "4.3";
+ case _4_3_0: return "4.3.0";
+ case _4_3_0CIBUILD: return "4.3.0-cibuild";
+ case _4_3_0SNAPSHOT1: return "4.3.0-snapshot1";
+ case _4_4: return "4.4";
+ case _4_4_0: return "4.4.0";
+ case _4_5: return "4.5";
+ case _4_5_0: return "4.5.0";
+ case _4_6: return "4.6";
+ case _4_6_0: return "4.6.0";
+ case _5_0: return "5.0";
+ case _5_0_0: return "5.0.0";
+ case _5_0_0CIBUILD: return "5.0.0-cibuild";
+ case _5_0_0SNAPSHOT1: return "5.0.0-snapshot1";
+ case _5_0_0SNAPSHOT2: return "5.0.0-snapshot2";
+ case _5_0_0BALLOT: return "5.0.0-ballot";
+ case _5_0_0SNAPSHOT3: return "5.0.0-snapshot3";
+ case _5_0_0DRAFTFINAL: return "5.0.0-draft-final";
+ case _6_0_0CIBUILD: return "6.0.0-cibuild";
+ case _6_0_0: return "6.0.0";
+ case _6_0_0_BALLOT1: return "6.0.0-ballot1";
+ case _6_0_0_BALLOT2: return "6.0.0-ballot2";
+ case NULL: return null;
+ default: return "?";
+ }
+ }
+ public String getSystem() {
+ switch (this) {
+ case _0_01: return "http://hl7.org/fhir/FHIR-version";
+ case _0_05: return "http://hl7.org/fhir/FHIR-version";
+ case _0_06: return "http://hl7.org/fhir/FHIR-version";
+ case _0_11: return "http://hl7.org/fhir/FHIR-version";
+ case _0_0: return "http://hl7.org/fhir/FHIR-version";
+ case _0_0_80: return "http://hl7.org/fhir/FHIR-version";
+ case _0_0_81: return "http://hl7.org/fhir/FHIR-version";
+ case _0_0_82: return "http://hl7.org/fhir/FHIR-version";
+ case _0_4: return "http://hl7.org/fhir/FHIR-version";
+ case _0_4_0: return "http://hl7.org/fhir/FHIR-version";
+ case _0_5: return "http://hl7.org/fhir/FHIR-version";
+ case _0_5_0: return "http://hl7.org/fhir/FHIR-version";
+ case _1_0: return "http://hl7.org/fhir/FHIR-version";
+ case _1_0_0: return "http://hl7.org/fhir/FHIR-version";
+ case _1_0_1: return "http://hl7.org/fhir/FHIR-version";
+ case _1_0_2: return "http://hl7.org/fhir/FHIR-version";
+ case _1_1: return "http://hl7.org/fhir/FHIR-version";
+ case _1_1_0: return "http://hl7.org/fhir/FHIR-version";
+ case _1_4: return "http://hl7.org/fhir/FHIR-version";
+ case _1_4_0: return "http://hl7.org/fhir/FHIR-version";
+ case _1_6: return "http://hl7.org/fhir/FHIR-version";
+ case _1_6_0: return "http://hl7.org/fhir/FHIR-version";
+ case _1_8: return "http://hl7.org/fhir/FHIR-version";
+ case _1_8_0: return "http://hl7.org/fhir/FHIR-version";
+ case _3_0: return "http://hl7.org/fhir/FHIR-version";
+ case _3_0_0: return "http://hl7.org/fhir/FHIR-version";
+ case _3_0_1: return "http://hl7.org/fhir/FHIR-version";
+ case _3_0_2: return "http://hl7.org/fhir/FHIR-version";
+ case _3_3: return "http://hl7.org/fhir/FHIR-version";
+ case _3_3_0: return "http://hl7.org/fhir/FHIR-version";
+ case _3_5: return "http://hl7.org/fhir/FHIR-version";
+ case _3_5_0: return "http://hl7.org/fhir/FHIR-version";
+ case _4_0: return "http://hl7.org/fhir/FHIR-version";
+ case _4_0_0: return "http://hl7.org/fhir/FHIR-version";
+ case _4_0_1: return "http://hl7.org/fhir/FHIR-version";
+ case _4_1: return "http://hl7.org/fhir/FHIR-version";
+ case _4_1_0: return "http://hl7.org/fhir/FHIR-version";
+ case _4_2: return "http://hl7.org/fhir/FHIR-version";
+ case _4_2_0: return "http://hl7.org/fhir/FHIR-version";
+ case _4_3: return "http://hl7.org/fhir/FHIR-version";
+ case _4_3_0: return "http://hl7.org/fhir/FHIR-version";
+ case _4_3_0CIBUILD: return "http://hl7.org/fhir/FHIR-version";
+ case _4_3_0SNAPSHOT1: return "http://hl7.org/fhir/FHIR-version";
+ case _4_4: return "http://hl7.org/fhir/FHIR-version";
+ case _4_4_0: return "http://hl7.org/fhir/FHIR-version";
+ case _4_5: return "http://hl7.org/fhir/FHIR-version";
+ case _4_5_0: return "http://hl7.org/fhir/FHIR-version";
+ case _4_6: return "http://hl7.org/fhir/FHIR-version";
+ case _4_6_0: return "http://hl7.org/fhir/FHIR-version";
+ case _5_0: return "http://hl7.org/fhir/FHIR-version";
+ case _5_0_0: return "http://hl7.org/fhir/FHIR-version";
+ case _5_0_0CIBUILD: return "http://hl7.org/fhir/FHIR-version";
+ case _5_0_0SNAPSHOT1: return "http://hl7.org/fhir/FHIR-version";
+ case _5_0_0SNAPSHOT2: return "http://hl7.org/fhir/FHIR-version";
+ case _5_0_0BALLOT: return "http://hl7.org/fhir/FHIR-version";
+ case _5_0_0SNAPSHOT3: return "http://hl7.org/fhir/FHIR-version";
+ case _5_0_0DRAFTFINAL: return "http://hl7.org/fhir/FHIR-version";
+ case _6_0_0CIBUILD: return "http://hl7.org/fhir/FHIR-version";
+ case _6_0_0: return "http://hl7.org/fhir/FHIR-version";
+ case _6_0_0_BALLOT1: return "http://hl7.org/fhir/FHIR-version";
+ case NULL: return null;
+ default: return "?";
+ }
+ }
+ public String getDefinition() {
+ switch (this) {
+ case _0_01: return "Oldest archived version of FHIR.";
+ case _0_05: return "1st Draft for Comment (Sept 2012 Ballot).";
+ case _0_06: return "2nd Draft for Comment (January 2013 Ballot).";
+ case _0_11: return "DSTU 1 Ballot version.";
+ case _0_0: return "DSTU 1 version.";
+ case _0_0_80: return "DSTU 1 Official version.";
+ case _0_0_81: return "DSTU 1 Official version Technical Errata #1.";
+ case _0_0_82: return "DSTU 1 Official version Technical Errata #2.";
+ case _0_4: return "January 2015 Ballot.";
+ case _0_4_0: return "Draft For Comment (January 2015 Ballot).";
+ case _0_5: return "May 2015 Ballot.";
+ case _0_5_0: return "DSTU 2 Ballot version (May 2015 Ballot).";
+ case _1_0: return "DSTU 2 version.";
+ case _1_0_0: return "DSTU 2 QA Preview + CQIF Ballot (Sep 2015).";
+ case _1_0_1: return "DSTU 2 (Official version).";
+ case _1_0_2: return "DSTU 2 (Official version) with 1 technical errata.";
+ case _1_1: return "GAO Ballot version.";
+ case _1_1_0: return "GAO Ballot + draft changes to main FHIR standard.";
+ case _1_4: return "Connectathon 12 (Montreal) version.";
+ case _1_4_0: return "CQF on FHIR Ballot + Connectathon 12 (Montreal).";
+ case _1_6: return "Connectathon 13 (Baltimore) version.";
+ case _1_6_0: return "FHIR STU3 Ballot + Connectathon 13 (Baltimore).";
+ case _1_8: return "Connectathon 14 (San Antonio) version.";
+ case _1_8_0: return "FHIR STU3 Candidate + Connectathon 14 (San Antonio).";
+ case _3_0: return "STU3 version.";
+ case _3_0_0: return "FHIR Release 3 (STU).";
+ case _3_0_1: return "FHIR Release 3 (STU) with 1 technical errata.";
+ case _3_0_2: return "FHIR Release 3 (STU) with 2 technical errata.";
+ case _3_3: return "R4 Ballot #1 version.";
+ case _3_3_0: return "R4 Ballot #1 + Connectaton 18 (Cologne).";
+ case _3_5: return "R4 Ballot #2 version.";
+ case _3_5_0: return "R4 Ballot #2 + Connectathon 19 (Baltimore).";
+ case _4_0: return "R4 version.";
+ case _4_0_0: return "FHIR Release 4 (Normative + STU).";
+ case _4_0_1: return "FHIR Release 4 (Normative + STU) with 1 technical errata.";
+ case _4_1: return "R4B Ballot #1 version.";
+ case _4_1_0: return "R4B Ballot #1 + Connectathon 27 (Virtual).";
+ case _4_2: return "R5 Preview #1 version.";
+ case _4_2_0: return "R5 Preview #1 + Connectathon 23 (Sydney).";
+ case _4_3: return "R4B version.";
+ case _4_3_0: return "FHIR Release 4B (Normative + STU).";
+ case _4_3_0CIBUILD: return "FHIR Release 4B CI-Builld.";
+ case _4_3_0SNAPSHOT1: return "FHIR Release 4B Snapshot #1.";
+ case _4_4: return "R5 Preview #2 version.";
+ case _4_4_0: return "R5 Preview #2 + Connectathon 24 (Virtual).";
+ case _4_5: return "R5 Preview #3 version.";
+ case _4_5_0: return "R5 Preview #3 + Connectathon 25 (Virtual).";
+ case _4_6: return "R5 Draft Ballot version.";
+ case _4_6_0: return "R5 Draft Ballot + Connectathon 27 (Virtual).";
+ case _5_0: return "R5 Versions.";
+ case _5_0_0: return "R5 Final Version.";
+ case _5_0_0CIBUILD: return "R5 Rolling ci-build.";
+ case _5_0_0SNAPSHOT1: return "R5 Preview #2.";
+ case _5_0_0SNAPSHOT2: return "R5 Interim tooling stage.";
+ case _5_0_0BALLOT: return "R5 Ballot.";
+ case _5_0_0SNAPSHOT3: return "R5 January 2023 Staging Release + Connectathon 32.";
+ case _5_0_0DRAFTFINAL: return "R5 Final QA.";
+ case _6_0_0CIBUILD: return "R6 Rolling ci-build.";
+ case _6_0_0: return "R6 Final Version.";
+ case _6_0_0_BALLOT1: return "R6 Ballot #1.";
+ case NULL: return null;
+ default: return "?";
+ }
+ }
+ public String getDisplay() {
+ switch (this) {
+ case _0_01: return "0.01";
+ case _0_05: return "0.05";
+ case _0_06: return "0.06";
+ case _0_11: return "0.11";
+ case _0_0: return "0.0";
+ case _0_0_80: return "0.0.80";
+ case _0_0_81: return "0.0.81";
+ case _0_0_82: return "0.0.82";
+ case _0_4: return "0.4";
+ case _0_4_0: return "0.4.0";
+ case _0_5: return "0.5";
+ case _0_5_0: return "0.5.0";
+ case _1_0: return "1.0";
+ case _1_0_0: return "1.0.0";
+ case _1_0_1: return "1.0.1";
+ case _1_0_2: return "1.0.2";
+ case _1_1: return "1.1";
+ case _1_1_0: return "1.1.0";
+ case _1_4: return "1.4";
+ case _1_4_0: return "1.4.0";
+ case _1_6: return "1.6";
+ case _1_6_0: return "1.6.0";
+ case _1_8: return "1.8";
+ case _1_8_0: return "1.8.0";
+ case _3_0: return "3.0";
+ case _3_0_0: return "3.0.0";
+ case _3_0_1: return "3.0.1";
+ case _3_0_2: return "3.0.2";
+ case _3_3: return "3.3";
+ case _3_3_0: return "3.3.0";
+ case _3_5: return "3.5";
+ case _3_5_0: return "3.5.0";
+ case _4_0: return "4.0";
+ case _4_0_0: return "4.0.0";
+ case _4_0_1: return "4.0.1";
+ case _4_1: return "4.1";
+ case _4_1_0: return "4.1.0";
+ case _4_2: return "4.2";
+ case _4_2_0: return "4.2.0";
+ case _4_3: return "4.3";
+ case _4_3_0: return "4.3.0";
+ case _4_3_0CIBUILD: return "4.3.0-cibuild";
+ case _4_3_0SNAPSHOT1: return "4.3.0-snapshot1";
+ case _4_4: return "4.4";
+ case _4_4_0: return "4.4.0";
+ case _4_5: return "4.5";
+ case _4_5_0: return "4.5.0";
+ case _4_6: return "4.6";
+ case _4_6_0: return "4.6.0";
+ case _5_0: return "5.0";
+ case _5_0_0: return "5.0.0";
+ case _5_0_0CIBUILD: return "5.0.0-cibuild";
+ case _5_0_0SNAPSHOT1: return "5.0.0-snapshot1";
+ case _5_0_0SNAPSHOT2: return "5.0.0-snapshot2";
+ case _5_0_0BALLOT: return "5.0.0-ballot";
+ case _5_0_0SNAPSHOT3: return "5.0.0-snapshot3";
+ case _5_0_0DRAFTFINAL: return "5.0.0-draft-final";
+ case _6_0_0CIBUILD: return "6.0.0-cibuild";
+ case _6_0_0: return "6.0.0";
+ case _6_0_0_BALLOT1: return "6.0.0-ballot1";
+ case _6_0_0_BALLOT2: return "6.0.0-ballot2";
+ case NULL: return null;
+ default: return "?";
+ }
+ }
+// manual code from configuration.txt:
+//public String toCode(int len) {
+// return toCode().substring(0, len);
+// }
+//
+//
+// @Override
+// public String toString() {
+// return toCode();
+// }
+//
+//
+// public boolean isR4B() {
+// return toCode().startsWith("4.1");
+// }
+//
+// end addition
}
- public static boolean isValidCode(String codeString) {
- if (codeString == null || "".equals(codeString))
- return false;
- if ("0.01".equals(codeString))
- return true;
- if ("0.05".equals(codeString))
- return true;
- if ("0.06".equals(codeString))
- return true;
- if ("0.11".equals(codeString))
- return true;
- if ("0.0".equals(codeString))
- return true;
- if ("0.0.80".equals(codeString))
- return true;
- if ("0.0.81".equals(codeString))
- return true;
- if ("0.0.82".equals(codeString))
- return true;
- if ("0.4".equals(codeString))
- return true;
- if ("0.4.0".equals(codeString))
- return true;
- if ("0.5".equals(codeString))
- return true;
- if ("0.5.0".equals(codeString))
- return true;
- if ("1.0".equals(codeString))
- return true;
- if ("1.0.0".equals(codeString))
- return true;
- if ("1.0.1".equals(codeString))
- return true;
- if ("1.0.2".equals(codeString))
- return true;
- if ("1.1".equals(codeString))
- return true;
- if ("1.1.0".equals(codeString))
- return true;
- if ("1.4".equals(codeString))
- return true;
- if ("1.4.0".equals(codeString))
- return true;
- if ("1.6".equals(codeString))
- return true;
- if ("1.6.0".equals(codeString))
- return true;
- if ("1.8".equals(codeString))
- return true;
- if ("1.8.0".equals(codeString))
- return true;
- if ("3.0".equals(codeString))
- return true;
- if ("3.0.0".equals(codeString))
- return true;
- if ("3.0.1".equals(codeString))
- return true;
- if ("3.0.2".equals(codeString))
- return true;
- if ("3.3".equals(codeString))
- return true;
- if ("3.3.0".equals(codeString))
- return true;
- if ("3.5".equals(codeString))
- return true;
- if ("3.5.0".equals(codeString))
- return true;
- if ("4.0".equals(codeString))
- return true;
- if ("4.0.0".equals(codeString))
- return true;
- if ("4.0.1".equals(codeString))
- return true;
- if ("4.1".equals(codeString))
- return true;
- if ("4.1.0".equals(codeString))
- return true;
- if ("4.2".equals(codeString))
- return true;
- if ("4.2.0".equals(codeString))
- return true;
- if ("4.3".equals(codeString))
- return true;
- if ("4.3.0".equals(codeString))
- return true;
- if ("4.4".equals(codeString))
- return true;
- if ("4.4.0".equals(codeString))
- return true;
- if ("4.5".equals(codeString))
- return true;
- if ("4.5.0".equals(codeString))
- return true;
- if ("4.6".equals(codeString))
- return true;
- if ("4.6.0".equals(codeString))
- return true;
- if ("5.0".equals(codeString))
- return true;
- if ("5.0.0".equals(codeString))
- return true;
- if ("5.0.0-cibuild".equals(codeString))
- return true;
- if ("5.0.0-snapshot1".equals(codeString))
- return true;
- if ("5.0.0-snapshot2".equals(codeString))
- return true;
- if ("5.0.0-ballot".equals(codeString))
- return true;
- return false;
- }
-
- public String toCode() {
- switch (this) {
- case _0_01:
- return "0.01";
- case _0_05:
- return "0.05";
- case _0_06:
- return "0.06";
- case _0_11:
- return "0.11";
- case _0_0:
- return "0.0";
- case _0_0_80:
- return "0.0.80";
- case _0_0_81:
- return "0.0.81";
- case _0_0_82:
- return "0.0.82";
- case _0_4:
- return "0.4";
- case _0_4_0:
- return "0.4.0";
- case _0_5:
- return "0.5";
- case _0_5_0:
- return "0.5.0";
- case _1_0:
- return "1.0";
- case _1_0_0:
- return "1.0.0";
- case _1_0_1:
- return "1.0.1";
- case _1_0_2:
- return "1.0.2";
- case _1_1:
- return "1.1";
- case _1_1_0:
- return "1.1.0";
- case _1_4:
- return "1.4";
- case _1_4_0:
- return "1.4.0";
- case _1_6:
- return "1.6";
- case _1_6_0:
- return "1.6.0";
- case _1_8:
- return "1.8";
- case _1_8_0:
- return "1.8.0";
- case _3_0:
- return "3.0";
- case _3_0_0:
- return "3.0.0";
- case _3_0_1:
- return "3.0.1";
- case _3_0_2:
- return "3.0.2";
- case _3_3:
- return "3.3";
- case _3_3_0:
- return "3.3.0";
- case _3_5:
- return "3.5";
- case _3_5_0:
- return "3.5.0";
- case _4_0:
- return "4.0";
- case _4_0_0:
- return "4.0.0";
- case _4_0_1:
- return "4.0.1";
- case _4_1:
- return "4.1";
- case _4_1_0:
- return "4.1.0";
- case _4_2:
- return "4.2";
- case _4_2_0:
- return "4.2.0";
- case _4_3:
- return "4.3";
- case _4_3_0:
- return "4.3.0";
- case _4_3_0_SNAPSHOT1:
- return "4.3.0-snapshot1";
- case _4_3_0_CIBUILD:
- return "4.3.0-cibuild";
- case _4_4:
- return "4.4";
- case _4_4_0:
- return "4.4.0";
- case _4_5:
- return "4.5";
- case _4_5_0:
- return "4.5.0";
- case _4_6:
- return "4.6";
- case _4_6_0:
- return "4.6.0";
- case _5_0:
- return "5.0";
- case _5_0_0:
- return "5.0.0";
- case _5_0_0CIBUILD:
- return "5.0.0-cibuild";
- case _5_0_0SNAPSHOT1:
- return "5.0.0-snapshot1";
- case _5_0_0SNAPSHOT2:
- return "5.0.0-snapshot2";
- case _5_0_0BALLOT:
- return "5.0.0-ballot";
- case _5_0_0SNAPSHOT3:
- return "5.0.0-snapshot3";
- case _5_0_0DRAFTFINAL:
- return "5.0.0-draft-final";
- case NULL:
- return null;
- default:
- return "?";
- }
- }
-
- public String getSystem() {
- switch (this) {
- case _0_01:
- return "http://hl7.org/fhir/FHIR-version";
- case _0_05:
- return "http://hl7.org/fhir/FHIR-version";
- case _0_06:
- return "http://hl7.org/fhir/FHIR-version";
- case _0_11:
- return "http://hl7.org/fhir/FHIR-version";
- case _0_0:
- return "http://hl7.org/fhir/FHIR-version";
- case _0_0_80:
- return "http://hl7.org/fhir/FHIR-version";
- case _0_0_81:
- return "http://hl7.org/fhir/FHIR-version";
- case _0_0_82:
- return "http://hl7.org/fhir/FHIR-version";
- case _0_4:
- return "http://hl7.org/fhir/FHIR-version";
- case _0_4_0:
- return "http://hl7.org/fhir/FHIR-version";
- case _0_5:
- return "http://hl7.org/fhir/FHIR-version";
- case _0_5_0:
- return "http://hl7.org/fhir/FHIR-version";
- case _1_0:
- return "http://hl7.org/fhir/FHIR-version";
- case _1_0_0:
- return "http://hl7.org/fhir/FHIR-version";
- case _1_0_1:
- return "http://hl7.org/fhir/FHIR-version";
- case _1_0_2:
- return "http://hl7.org/fhir/FHIR-version";
- case _1_1:
- return "http://hl7.org/fhir/FHIR-version";
- case _1_1_0:
- return "http://hl7.org/fhir/FHIR-version";
- case _1_4:
- return "http://hl7.org/fhir/FHIR-version";
- case _1_4_0:
- return "http://hl7.org/fhir/FHIR-version";
- case _1_6:
- return "http://hl7.org/fhir/FHIR-version";
- case _1_6_0:
- return "http://hl7.org/fhir/FHIR-version";
- case _1_8:
- return "http://hl7.org/fhir/FHIR-version";
- case _1_8_0:
- return "http://hl7.org/fhir/FHIR-version";
- case _3_0:
- return "http://hl7.org/fhir/FHIR-version";
- case _3_0_0:
- return "http://hl7.org/fhir/FHIR-version";
- case _3_0_1:
- return "http://hl7.org/fhir/FHIR-version";
- case _3_0_2:
- return "http://hl7.org/fhir/FHIR-version";
- case _3_3:
- return "http://hl7.org/fhir/FHIR-version";
- case _3_3_0:
- return "http://hl7.org/fhir/FHIR-version";
- case _3_5:
- return "http://hl7.org/fhir/FHIR-version";
- case _3_5_0:
- return "http://hl7.org/fhir/FHIR-version";
- case _4_0:
- return "http://hl7.org/fhir/FHIR-version";
- case _4_0_0:
- return "http://hl7.org/fhir/FHIR-version";
- case _4_0_1:
- return "http://hl7.org/fhir/FHIR-version";
- case _4_1:
- return "http://hl7.org/fhir/FHIR-version";
- case _4_1_0:
- return "http://hl7.org/fhir/FHIR-version";
- case _4_2:
- return "http://hl7.org/fhir/FHIR-version";
- case _4_2_0:
- return "http://hl7.org/fhir/FHIR-version";
- case _4_3:
- return "http://hl7.org/fhir/FHIR-version";
- case _4_3_0:
- return "http://hl7.org/fhir/FHIR-version";
- case _4_3_0_SNAPSHOT1:
- return "http://hl7.org/fhir/FHIR-version";
- case _4_3_0_CIBUILD:
- return "http://hl7.org/fhir/FHIR-version";
- case _4_4:
- return "http://hl7.org/fhir/FHIR-version";
- case _4_4_0:
- return "http://hl7.org/fhir/FHIR-version";
- case _4_5:
- return "http://hl7.org/fhir/FHIR-version";
- case _4_5_0:
- return "http://hl7.org/fhir/FHIR-version";
- case _4_6:
- return "http://hl7.org/fhir/FHIR-version";
- case _4_6_0:
- return "http://hl7.org/fhir/FHIR-version";
- case _5_0:
- return "http://hl7.org/fhir/FHIR-version";
- case _5_0_0:
- return "http://hl7.org/fhir/FHIR-version";
- case _5_0_0CIBUILD:
- return "http://hl7.org/fhir/FHIR-version";
- case _5_0_0SNAPSHOT1:
- return "http://hl7.org/fhir/FHIR-version";
- case _5_0_0SNAPSHOT2:
- return "http://hl7.org/fhir/FHIR-version";
- case _5_0_0BALLOT:
- return "http://hl7.org/fhir/FHIR-version";
- case _5_0_0SNAPSHOT3:
- return "http://hl7.org/fhir/FHIR-version";
- case _5_0_0DRAFTFINAL:
- return "http://hl7.org/fhir/FHIR-version";
- case NULL:
- return null;
- default:
- return "?";
- }
- }
-
- public String getDefinition() {
- switch (this) {
- case _0_01:
- return "Oldest archived version of FHIR.";
- case _0_05:
- return "1st Draft for Comment (Sept 2012 Ballot).";
- case _0_06:
- return "2nd Draft for Comment (January 2013 Ballot).";
- case _0_11:
- return "DSTU 1 Ballot version.";
- case _0_0:
- return "DSTU 1 version.";
- case _0_0_80:
- return "DSTU 1 Official version.";
- case _0_0_81:
- return "DSTU 1 Official version Technical Errata #1.";
- case _0_0_82:
- return "DSTU 1 Official version Technical Errata #2.";
- case _0_4:
- return "January 2015 Ballot.";
- case _0_4_0:
- return "Draft For Comment (January 2015 Ballot).";
- case _0_5:
- return "May 2015 Ballot.";
- case _0_5_0:
- return "DSTU 2 Ballot version (May 2015 Ballot).";
- case _1_0:
- return "DSTU 2 version.";
- case _1_0_0:
- return "DSTU 2 QA Preview + CQIF Ballot (Sep 2015).";
- case _1_0_1:
- return "DSTU 2 (Official version).";
- case _1_0_2:
- return "DSTU 2 (Official version) with 1 technical errata.";
- case _1_1:
- return "GAO Ballot version.";
- case _1_1_0:
- return "GAO Ballot + draft changes to main FHIR standard.";
- case _1_4:
- return "Connectathon 12 (Montreal) version.";
- case _1_4_0:
- return "CQF on FHIR Ballot + Connectathon 12 (Montreal).";
- case _1_6:
- return "Connectathon 13 (Baltimore) version.";
- case _1_6_0:
- return "FHIR STU3 Ballot + Connectathon 13 (Baltimore).";
- case _1_8:
- return "Connectathon 14 (San Antonio) version.";
- case _1_8_0:
- return "FHIR STU3 Candidate + Connectathon 14 (San Antonio).";
- case _3_0:
- return "STU3 version.";
- case _3_0_0:
- return "FHIR Release 3 (STU).";
- case _3_0_1:
- return "FHIR Release 3 (STU) with 1 technical errata.";
- case _3_0_2:
- return "FHIR Release 3 (STU) with 2 technical errata.";
- case _3_3:
- return "R4 Ballot #1 version.";
- case _3_3_0:
- return "R4 Ballot #1 + Connectaton 18 (Cologne).";
- case _3_5:
- return "R4 Ballot #2 version.";
- case _3_5_0:
- return "R4 Ballot #2 + Connectathon 19 (Baltimore).";
- case _4_0:
- return "R4 version.";
- case _4_0_0:
- return "FHIR Release 4 (Normative + STU).";
- case _4_0_1:
- return "FHIR Release 4 (Normative + STU) with 1 technical errata.";
- case _4_1:
- return "R4B Ballot #1 version.";
- case _4_1_0:
- return "R4B Ballot #1 + Connectathon 27 (Virtual).";
- case _4_2:
- return "R5 Preview #1 version.";
- case _4_2_0:
- return "R5 Preview #1 + Connectathon 23 (Sydney).";
- case _4_3_0_SNAPSHOT1:
- return "FHIR Release 4B Snapshot #1";
- case _4_3_0_CIBUILD:
- return "FHIR Release 4B CI-Builld";
- case _4_3:
- return "R4B version.";
- case _4_3_0:
- return "FHIR Release 4B (Normative + STU).";
- case _4_4:
- return "R5 Preview #2 version.";
- case _4_4_0:
- return "R5 Preview #2 + Connectathon 24 (Virtual).";
- case _4_5:
- return "R5 Preview #3 version.";
- case _4_5_0:
- return "R5 Preview #3 + Connectathon 25 (Virtual).";
- case _4_6:
- return "R5 Draft Ballot version.";
- case _4_6_0:
- return "R5 Draft Ballot + Connectathon 27 (Virtual).";
- case _5_0:
- return "R5 Versions.";
- case _5_0_0:
- return "R5 Final Version.";
- case _5_0_0CIBUILD:
- return "R5 Rolling ci-build.";
- case _5_0_0SNAPSHOT1:
- return "R5 Preview #2.";
- case _5_0_0SNAPSHOT2:
- return "R5 Interim tooling stage.";
- case _5_0_0BALLOT:
- return "R5 Ballot.";
- case _5_0_0SNAPSHOT3:
- return "R5 Connectathon 32 release.";
- case _5_0_0DRAFTFINAL:
- return "R5 Final QA.";
- case NULL:
- return null;
- default:
- return "?";
- }
- }
-
- public String getDisplay() {
- switch (this) {
- case _0_01:
- return "0.01";
- case _0_05:
- return "0.05";
- case _0_06:
- return "0.06";
- case _0_11:
- return "0.11";
- case _0_0:
- return "0.0";
- case _0_0_80:
- return "0.0.80";
- case _0_0_81:
- return "0.0.81";
- case _0_0_82:
- return "0.0.82";
- case _0_4:
- return "0.4";
- case _0_4_0:
- return "0.4.0";
- case _0_5:
- return "0.5";
- case _0_5_0:
- return "0.5.0";
- case _1_0:
- return "1.0";
- case _1_0_0:
- return "1.0.0";
- case _1_0_1:
- return "1.0.1";
- case _1_0_2:
- return "1.0.2";
- case _1_1:
- return "1.1";
- case _1_1_0:
- return "1.1.0";
- case _1_4:
- return "1.4";
- case _1_4_0:
- return "1.4.0";
- case _1_6:
- return "1.6";
- case _1_6_0:
- return "1.6.0";
- case _1_8:
- return "1.8";
- case _1_8_0:
- return "1.8.0";
- case _3_0:
- return "3.0";
- case _3_0_0:
- return "3.0.0";
- case _3_0_1:
- return "3.0.1";
- case _3_0_2:
- return "3.0.2";
- case _3_3:
- return "3.3";
- case _3_3_0:
- return "3.3.0";
- case _3_5:
- return "3.5";
- case _3_5_0:
- return "3.5.0";
- case _4_0:
- return "4.0";
- case _4_0_0:
- return "4.0.0";
- case _4_0_1:
- return "4.0.1";
- case _4_1:
- return "4.1";
- case _4_1_0:
- return "4.1.0";
- case _4_2:
- return "4.2";
- case _4_2_0:
- return "4.2.0";
- case _4_3:
- return "4.3";
- case _4_3_0:
- return "4.3.0";
- case _4_3_0_SNAPSHOT1:
- return "4.3.0-snapshot";
- case _4_3_0_CIBUILD:
- return "4.3.0-cibuild";
- case _4_4:
- return "4.4";
- case _4_4_0:
- return "4.4.0";
- case _4_5:
- return "4.5";
- case _4_5_0:
- return "4.5.0";
- case _4_6:
- return "4.6";
- case _4_6_0:
- return "4.6.0";
- case _5_0:
- return "5.0";
- case _5_0_0:
- return "5.0.0";
- case _5_0_0CIBUILD:
- return "5.0.0-cibuild";
- case _5_0_0SNAPSHOT1:
- return "5.0.0-snapshot1";
- case _5_0_0SNAPSHOT2:
- return "5.0.0-snapshot2";
- case _5_0_0BALLOT:
- return "5.0.0-ballot";
- case _5_0_0SNAPSHOT3:
- return "5.0.0-snapshot3";
- case _5_0_0DRAFTFINAL:
- return "5.0.0-draft-final";
- case NULL:
- return null;
- default:
- return "?";
- }
- }
- }
-
public static class FHIRVersionEnumFactory implements EnumFactory {
public FHIRVersion fromCode(String codeString) throws IllegalArgumentException {
if (codeString == null || "".equals(codeString))
- if (codeString == null || "".equals(codeString))
- return null;
- if ("0.01".equals(codeString))
- return FHIRVersion._0_01;
- if ("0.05".equals(codeString))
- return FHIRVersion._0_05;
- if ("0.06".equals(codeString))
- return FHIRVersion._0_06;
- if ("0.11".equals(codeString))
- return FHIRVersion._0_11;
- if ("0.0.80".equals(codeString))
- return FHIRVersion._0_0_80;
- if ("0.0.81".equals(codeString))
- return FHIRVersion._0_0_81;
- if ("0.0.82".equals(codeString))
- return FHIRVersion._0_0_82;
- if ("0.4.0".equals(codeString))
- return FHIRVersion._0_4_0;
- if ("0.5".equals(codeString))
- return FHIRVersion._0_5;
- if ("0.5.0".equals(codeString))
- return FHIRVersion._0_5_0;
- if ("1.0".equals(codeString))
- return FHIRVersion._1_0;
- if ("1.0.0".equals(codeString))
- return FHIRVersion._1_0_0;
- if ("1.0.1".equals(codeString))
- return FHIRVersion._1_0_1;
- if ("1.0.2".equals(codeString))
- return FHIRVersion._1_0_2;
- if ("1.1".equals(codeString))
- return FHIRVersion._1_1;
- if ("1.1.0".equals(codeString))
- return FHIRVersion._1_1_0;
- if ("1.4".equals(codeString))
- return FHIRVersion._1_4;
- if ("1.4.0".equals(codeString))
- return FHIRVersion._1_4_0;
- if ("1.6".equals(codeString))
- return FHIRVersion._1_6;
- if ("1.6.0".equals(codeString))
- return FHIRVersion._1_6_0;
- if ("1.8".equals(codeString))
- return FHIRVersion._1_8;
- if ("1.8.0".equals(codeString))
- return FHIRVersion._1_8_0;
- if ("3.0".equals(codeString))
- return FHIRVersion._3_0;
- if ("3.0.0".equals(codeString))
- return FHIRVersion._3_0_0;
- if ("3.0.1".equals(codeString))
- return FHIRVersion._3_0_1;
- if ("3.0.2".equals(codeString))
- return FHIRVersion._3_0_2;
- if ("3.3".equals(codeString))
- return FHIRVersion._3_3;
- if ("3.3.0".equals(codeString))
- return FHIRVersion._3_3_0;
- if ("3.5".equals(codeString))
- return FHIRVersion._3_5;
- if ("3.5.0".equals(codeString))
- return FHIRVersion._3_5_0;
- if ("4.0".equals(codeString))
- return FHIRVersion._4_0;
- if ("4.0.0".equals(codeString))
- return FHIRVersion._4_0_0;
- if ("4.0.1".equals(codeString))
- return FHIRVersion._4_0_1;
- if ("4.1".equals(codeString))
- return FHIRVersion._4_1;
- if ("4.1.0".equals(codeString))
- return FHIRVersion._4_1_0;
- if ("4.2".equals(codeString))
- return FHIRVersion._4_2;
- if ("4.2.0".equals(codeString))
- return FHIRVersion._4_2_0;
- if ("4.3".equals(codeString))
- return FHIRVersion._4_3;
- if ("4.3.0".equals(codeString))
- return FHIRVersion._4_3_0;
- if ("4.3.0-snapshot1".equalsIgnoreCase(codeString))
- return FHIRVersion._4_3_0_SNAPSHOT1;
- if ("4.3.0-cibuild".equalsIgnoreCase(codeString))
- return FHIRVersion._4_3_0_CIBUILD;
- if ("4.4".equals(codeString))
- return FHIRVersion._4_4;
- if ("4.4.0".equals(codeString))
- return FHIRVersion._4_4_0;
- if ("4.5".equals(codeString))
- return FHIRVersion._4_5;
- if ("4.5.0".equals(codeString))
- return FHIRVersion._4_5_0;
- if ("4.6".equals(codeString))
- return FHIRVersion._4_6;
- if ("4.6.0".equals(codeString))
- return FHIRVersion._4_6_0;
- if ("5.0".equals(codeString))
- return FHIRVersion._5_0;
- if ("5.0.0".equals(codeString))
- return FHIRVersion._5_0_0;
- if ("5.0.0-cibuild".equals(codeString))
- return FHIRVersion._5_0_0CIBUILD;
- if ("5.0.0-snapshot1".equals(codeString))
- return FHIRVersion._5_0_0SNAPSHOT1;
- if ("5.0.0-snapshot2".equals(codeString))
- return FHIRVersion._5_0_0SNAPSHOT2;
- if ("5.0.0-ballot".equals(codeString))
- return FHIRVersion._5_0_0BALLOT;
- if ("5.0.0-snapshot3".equals(codeString))
- return FHIRVersion._5_0_0SNAPSHOT3;
- if ("5.0.0-draft-final".equals(codeString))
- return FHIRVersion._5_0_0DRAFTFINAL;
- throw new IllegalArgumentException("Unknown FHIRVersion code '" + codeString + "'");
- }
-
- public Enumeration fromType(PrimitiveType> code) throws FHIRException {
- if (code == null)
- return null;
- if (code.isEmpty())
- return new Enumeration(this, FHIRVersion.NULL, code);
- String codeString = code.asStringValue();
- if (codeString == null || "".equals(codeString))
- return new Enumeration(this, FHIRVersion.NULL, code);
- if ("0.01".equals(codeString))
- return new Enumeration(this, FHIRVersion._0_01, code);
- if ("0.05".equals(codeString))
- return new Enumeration(this, FHIRVersion._0_05, code);
- if ("0.06".equals(codeString))
- return new Enumeration(this, FHIRVersion._0_06, code);
- if ("0.11".equals(codeString))
- return new Enumeration(this, FHIRVersion._0_11, code);
- if ("0.0".equals(codeString))
- return new Enumeration(this, FHIRVersion._0_0, code);
- if ("0.0.80".equals(codeString))
- return new Enumeration(this, FHIRVersion._0_0_80, code);
- if ("0.0.81".equals(codeString))
- return new Enumeration(this, FHIRVersion._0_0_81, code);
- if ("0.0.82".equals(codeString))
- return new Enumeration(this, FHIRVersion._0_0_82, code);
- if ("0.4".equals(codeString))
- return new Enumeration(this, FHIRVersion._0_4, code);
- if ("0.4.0".equals(codeString))
- return new Enumeration(this, FHIRVersion._0_4_0, code);
- if ("0.5".equals(codeString))
- return new Enumeration(this, FHIRVersion._0_5, code);
- if ("0.5.0".equals(codeString))
- return new Enumeration(this, FHIRVersion._0_5_0, code);
- if ("1.0".equals(codeString))
- return new Enumeration(this, FHIRVersion._1_0, code);
- if ("1.0.0".equals(codeString))
- return new Enumeration(this, FHIRVersion._1_0_0, code);
- if ("1.0.1".equals(codeString))
- return new Enumeration(this, FHIRVersion._1_0_1, code);
- if ("1.0.2".equals(codeString))
- return new Enumeration(this, FHIRVersion._1_0_2, code);
- if ("1.1".equals(codeString))
- return new Enumeration(this, FHIRVersion._1_1, code);
- if ("1.1.0".equals(codeString))
- return new Enumeration(this, FHIRVersion._1_1_0, code);
- if ("1.4".equals(codeString))
- return new Enumeration(this, FHIRVersion._1_4, code);
- if ("1.4.0".equals(codeString))
- return new Enumeration(this, FHIRVersion._1_4_0, code);
- if ("1.6".equals(codeString))
- return new Enumeration(this, FHIRVersion._1_6, code);
- if ("1.6.0".equals(codeString))
- return new Enumeration(this, FHIRVersion._1_6_0, code);
- if ("1.8".equals(codeString))
- return new Enumeration(this, FHIRVersion._1_8, code);
- if ("1.8.0".equals(codeString))
- return new Enumeration(this, FHIRVersion._1_8_0, code);
- if ("3.0".equals(codeString))
- return new Enumeration(this, FHIRVersion._3_0, code);
- if ("3.0.0".equals(codeString))
- return new Enumeration(this, FHIRVersion._3_0_0, code);
- if ("3.0.1".equals(codeString))
- return new Enumeration(this, FHIRVersion._3_0_1, code);
- if ("3.0.2".equals(codeString))
- return new Enumeration(this, FHIRVersion._3_0_2, code);
- if ("3.3".equals(codeString))
- return new Enumeration(this, FHIRVersion._3_3, code);
- if ("3.3.0".equals(codeString))
- return new Enumeration(this, FHIRVersion._3_3_0, code);
- if ("3.5".equals(codeString))
- return new Enumeration(this, FHIRVersion._3_5, code);
- if ("3.5.0".equals(codeString))
- return new Enumeration(this, FHIRVersion._3_5_0, code);
- if ("4.0".equals(codeString))
- return new Enumeration(this, FHIRVersion._4_0, code);
- if ("4.0.0".equals(codeString))
- return new Enumeration(this, FHIRVersion._4_0_0, code);
- if ("4.0.1".equals(codeString))
- return new Enumeration(this, FHIRVersion._4_0_1, code);
- if ("4.1".equals(codeString))
- return new Enumeration(this, FHIRVersion._4_1, code);
- if ("4.1.0".equals(codeString))
- return new Enumeration(this, FHIRVersion._4_1_0, code);
- if ("4.2".equals(codeString))
- return new Enumeration(this, FHIRVersion._4_2, code);
- if ("4.2.0".equals(codeString))
- return new Enumeration(this, FHIRVersion._4_2_0, code);
- if ("4.3".equals(codeString))
- return new Enumeration(this, FHIRVersion._4_3, code);
- if ("4.3.0".equals(codeString))
- return new Enumeration(this, FHIRVersion._4_3_0, code);
- if ("4.3.0-snapshot1".equals(codeString))
- return new Enumeration(this, FHIRVersion._4_3_0_SNAPSHOT1, code);
- if ("4.3.0-cibuild".equals(codeString))
- return new Enumeration(this, FHIRVersion._4_3_0_CIBUILD, code);
- if ("4.4".equals(codeString))
- return new Enumeration(this, FHIRVersion._4_4, code);
- if ("4.4.0".equals(codeString))
- return new Enumeration(this, FHIRVersion._4_4_0, code);
- if ("4.5".equals(codeString))
- return new Enumeration(this, FHIRVersion._4_5, code);
- if ("4.5.0".equals(codeString))
- return new Enumeration(this, FHIRVersion._4_5_0, code);
- if ("4.6".equals(codeString))
- return new Enumeration(this, FHIRVersion._4_6, code);
- if ("4.6.0".equals(codeString))
- return new Enumeration(this, FHIRVersion._4_6_0, code);
- if ("5.0".equals(codeString))
- return new Enumeration(this, FHIRVersion._5_0, code);
- if ("5.0.0".equals(codeString))
- return new Enumeration(this, FHIRVersion._5_0_0, code);
- if ("5.0.0-cibuild".equals(codeString))
- return new Enumeration(this, FHIRVersion._5_0_0CIBUILD, code);
- if ("5.0.0-snapshot1".equals(codeString))
- return new Enumeration(this, FHIRVersion._5_0_0SNAPSHOT1, code);
- if ("5.0.0-snapshot2".equals(codeString))
- return new Enumeration(this, FHIRVersion._5_0_0SNAPSHOT2, code);
- if ("5.0.0-ballot".equals(codeString))
- return new Enumeration(this, FHIRVersion._5_0_0BALLOT, code);
- if ("5.0.0-snapshot3".equals(codeString))
- return new Enumeration(this, FHIRVersion._5_0_0SNAPSHOT3, code);
- if ("5.0.0-draft-final".equals(codeString))
- return new Enumeration(this, FHIRVersion._5_0_0DRAFTFINAL, code);
- throw new FHIRException("Unknown FHIRVersion code '" + codeString + "'");
- }
+ if (codeString == null || "".equals(codeString))
+ return null;
+ if ("0.01".equals(codeString))
+ return FHIRVersion._0_01;
+ if ("0.05".equals(codeString))
+ return FHIRVersion._0_05;
+ if ("0.06".equals(codeString))
+ return FHIRVersion._0_06;
+ if ("0.11".equals(codeString))
+ return FHIRVersion._0_11;
+ if ("0.0".equals(codeString))
+ return FHIRVersion._0_0;
+ if ("0.0.80".equals(codeString))
+ return FHIRVersion._0_0_80;
+ if ("0.0.81".equals(codeString))
+ return FHIRVersion._0_0_81;
+ if ("0.0.82".equals(codeString))
+ return FHIRVersion._0_0_82;
+ if ("0.4".equals(codeString))
+ return FHIRVersion._0_4;
+ if ("0.4.0".equals(codeString))
+ return FHIRVersion._0_4_0;
+ if ("0.5".equals(codeString))
+ return FHIRVersion._0_5;
+ if ("0.5.0".equals(codeString))
+ return FHIRVersion._0_5_0;
+ if ("1.0".equals(codeString))
+ return FHIRVersion._1_0;
+ if ("1.0.0".equals(codeString))
+ return FHIRVersion._1_0_0;
+ if ("1.0.1".equals(codeString))
+ return FHIRVersion._1_0_1;
+ if ("1.0.2".equals(codeString))
+ return FHIRVersion._1_0_2;
+ if ("1.1".equals(codeString))
+ return FHIRVersion._1_1;
+ if ("1.1.0".equals(codeString))
+ return FHIRVersion._1_1_0;
+ if ("1.4".equals(codeString))
+ return FHIRVersion._1_4;
+ if ("1.4.0".equals(codeString))
+ return FHIRVersion._1_4_0;
+ if ("1.6".equals(codeString))
+ return FHIRVersion._1_6;
+ if ("1.6.0".equals(codeString))
+ return FHIRVersion._1_6_0;
+ if ("1.8".equals(codeString))
+ return FHIRVersion._1_8;
+ if ("1.8.0".equals(codeString))
+ return FHIRVersion._1_8_0;
+ if ("3.0".equals(codeString))
+ return FHIRVersion._3_0;
+ if ("3.0.0".equals(codeString))
+ return FHIRVersion._3_0_0;
+ if ("3.0.1".equals(codeString))
+ return FHIRVersion._3_0_1;
+ if ("3.0.2".equals(codeString))
+ return FHIRVersion._3_0_2;
+ if ("3.3".equals(codeString))
+ return FHIRVersion._3_3;
+ if ("3.3.0".equals(codeString))
+ return FHIRVersion._3_3_0;
+ if ("3.5".equals(codeString))
+ return FHIRVersion._3_5;
+ if ("3.5.0".equals(codeString))
+ return FHIRVersion._3_5_0;
+ if ("4.0".equals(codeString))
+ return FHIRVersion._4_0;
+ if ("4.0.0".equals(codeString))
+ return FHIRVersion._4_0_0;
+ if ("4.0.1".equals(codeString))
+ return FHIRVersion._4_0_1;
+ if ("4.1".equals(codeString))
+ return FHIRVersion._4_1;
+ if ("4.1.0".equals(codeString))
+ return FHIRVersion._4_1_0;
+ if ("4.2".equals(codeString))
+ return FHIRVersion._4_2;
+ if ("4.2.0".equals(codeString))
+ return FHIRVersion._4_2_0;
+ if ("4.3".equals(codeString))
+ return FHIRVersion._4_3;
+ if ("4.3.0".equals(codeString))
+ return FHIRVersion._4_3_0;
+ if ("4.3.0-cibuild".equals(codeString))
+ return FHIRVersion._4_3_0CIBUILD;
+ if ("4.3.0-snapshot1".equals(codeString))
+ return FHIRVersion._4_3_0SNAPSHOT1;
+ if ("4.4".equals(codeString))
+ return FHIRVersion._4_4;
+ if ("4.4.0".equals(codeString))
+ return FHIRVersion._4_4_0;
+ if ("4.5".equals(codeString))
+ return FHIRVersion._4_5;
+ if ("4.5.0".equals(codeString))
+ return FHIRVersion._4_5_0;
+ if ("4.6".equals(codeString))
+ return FHIRVersion._4_6;
+ if ("4.6.0".equals(codeString))
+ return FHIRVersion._4_6_0;
+ if ("5.0".equals(codeString))
+ return FHIRVersion._5_0;
+ if ("5.0.0".equals(codeString))
+ return FHIRVersion._5_0_0;
+ if ("5.0.0-cibuild".equals(codeString))
+ return FHIRVersion._5_0_0CIBUILD;
+ if ("5.0.0-snapshot1".equals(codeString))
+ return FHIRVersion._5_0_0SNAPSHOT1;
+ if ("5.0.0-snapshot2".equals(codeString))
+ return FHIRVersion._5_0_0SNAPSHOT2;
+ if ("5.0.0-ballot".equals(codeString))
+ return FHIRVersion._5_0_0BALLOT;
+ if ("5.0.0-snapshot3".equals(codeString))
+ return FHIRVersion._5_0_0SNAPSHOT3;
+ if ("5.0.0-draft-final".equals(codeString))
+ return FHIRVersion._5_0_0DRAFTFINAL;
+ if ("6.0.0-cibuild".equals(codeString))
+ return FHIRVersion._6_0_0CIBUILD;
+ if ("6.0.0".equals(codeString))
+ return FHIRVersion._6_0_0;
+ if ("6.0.0-ballot1".equals(codeString))
+ return FHIRVersion._6_0_0_BALLOT1;
+ if ("6.0.0-ballot2".equals(codeString))
+ return FHIRVersion._6_0_0_BALLOT2;
+ throw new IllegalArgumentException("Unknown FHIRVersion code '"+codeString+"'");
+ }
+ public Enumeration fromType(PrimitiveType> code) throws FHIRException {
+ if (code == null)
+ return null;
+ if (code.isEmpty())
+ return new Enumeration(this, FHIRVersion.NULL, code);
+ String codeString = ((PrimitiveType) code).asStringValue();
+ if (codeString == null || "".equals(codeString))
+ return new Enumeration(this, FHIRVersion.NULL, code);
+ if ("0.01".equals(codeString))
+ return new Enumeration(this, FHIRVersion._0_01, code);
+ if ("0.05".equals(codeString))
+ return new Enumeration(this, FHIRVersion._0_05, code);
+ if ("0.06".equals(codeString))
+ return new Enumeration(this, FHIRVersion._0_06, code);
+ if ("0.11".equals(codeString))
+ return new Enumeration(this, FHIRVersion._0_11, code);
+ if ("0.0".equals(codeString))
+ return new Enumeration(this, FHIRVersion._0_0, code);
+ if ("0.0.80".equals(codeString))
+ return new Enumeration(this, FHIRVersion._0_0_80, code);
+ if ("0.0.81".equals(codeString))
+ return new Enumeration(this, FHIRVersion._0_0_81, code);
+ if ("0.0.82".equals(codeString))
+ return new Enumeration(this, FHIRVersion._0_0_82, code);
+ if ("0.4".equals(codeString))
+ return new Enumeration(this, FHIRVersion._0_4, code);
+ if ("0.4.0".equals(codeString))
+ return new Enumeration(this, FHIRVersion._0_4_0, code);
+ if ("0.5".equals(codeString))
+ return new Enumeration(this, FHIRVersion._0_5, code);
+ if ("0.5.0".equals(codeString))
+ return new Enumeration(this, FHIRVersion._0_5_0, code);
+ if ("1.0".equals(codeString))
+ return new Enumeration(this, FHIRVersion._1_0, code);
+ if ("1.0.0".equals(codeString))
+ return new Enumeration(this, FHIRVersion._1_0_0, code);
+ if ("1.0.1".equals(codeString))
+ return new Enumeration(this, FHIRVersion._1_0_1, code);
+ if ("1.0.2".equals(codeString))
+ return new Enumeration(this, FHIRVersion._1_0_2, code);
+ if ("1.1".equals(codeString))
+ return new Enumeration(this, FHIRVersion._1_1, code);
+ if ("1.1.0".equals(codeString))
+ return new Enumeration(this, FHIRVersion._1_1_0, code);
+ if ("1.4".equals(codeString))
+ return new Enumeration(this, FHIRVersion._1_4, code);
+ if ("1.4.0".equals(codeString))
+ return new Enumeration(this, FHIRVersion._1_4_0, code);
+ if ("1.6".equals(codeString))
+ return new Enumeration(this, FHIRVersion._1_6, code);
+ if ("1.6.0".equals(codeString))
+ return new Enumeration(this, FHIRVersion._1_6_0, code);
+ if ("1.8".equals(codeString))
+ return new Enumeration(this, FHIRVersion._1_8, code);
+ if ("1.8.0".equals(codeString))
+ return new Enumeration(this, FHIRVersion._1_8_0, code);
+ if ("3.0".equals(codeString))
+ return new Enumeration(this, FHIRVersion._3_0, code);
+ if ("3.0.0".equals(codeString))
+ return new Enumeration(this, FHIRVersion._3_0_0, code);
+ if ("3.0.1".equals(codeString))
+ return new Enumeration(this, FHIRVersion._3_0_1, code);
+ if ("3.0.2".equals(codeString))
+ return new Enumeration(this, FHIRVersion._3_0_2, code);
+ if ("3.3".equals(codeString))
+ return new Enumeration(this, FHIRVersion._3_3, code);
+ if ("3.3.0".equals(codeString))
+ return new Enumeration(this, FHIRVersion._3_3_0, code);
+ if ("3.5".equals(codeString))
+ return new Enumeration(this, FHIRVersion._3_5, code);
+ if ("3.5.0".equals(codeString))
+ return new Enumeration(this, FHIRVersion._3_5_0, code);
+ if ("4.0".equals(codeString))
+ return new Enumeration(this, FHIRVersion._4_0, code);
+ if ("4.0.0".equals(codeString))
+ return new Enumeration(this, FHIRVersion._4_0_0, code);
+ if ("4.0.1".equals(codeString))
+ return new Enumeration(this, FHIRVersion._4_0_1, code);
+ if ("4.1".equals(codeString))
+ return new Enumeration(this, FHIRVersion._4_1, code);
+ if ("4.1.0".equals(codeString))
+ return new Enumeration(this, FHIRVersion._4_1_0, code);
+ if ("4.2".equals(codeString))
+ return new Enumeration(this, FHIRVersion._4_2, code);
+ if ("4.2.0".equals(codeString))
+ return new Enumeration(this, FHIRVersion._4_2_0, code);
+ if ("4.3".equals(codeString))
+ return new Enumeration(this, FHIRVersion._4_3, code);
+ if ("4.3.0".equals(codeString))
+ return new Enumeration(this, FHIRVersion._4_3_0, code);
+ if ("4.3.0-cibuild".equals(codeString))
+ return new Enumeration(this, FHIRVersion._4_3_0CIBUILD, code);
+ if ("4.3.0-snapshot1".equals(codeString))
+ return new Enumeration(this, FHIRVersion._4_3_0SNAPSHOT1, code);
+ if ("4.4".equals(codeString))
+ return new Enumeration(this, FHIRVersion._4_4, code);
+ if ("4.4.0".equals(codeString))
+ return new Enumeration(this, FHIRVersion._4_4_0, code);
+ if ("4.5".equals(codeString))
+ return new Enumeration(this, FHIRVersion._4_5, code);
+ if ("4.5.0".equals(codeString))
+ return new Enumeration(this, FHIRVersion._4_5_0, code);
+ if ("4.6".equals(codeString))
+ return new Enumeration(this, FHIRVersion._4_6, code);
+ if ("4.6.0".equals(codeString))
+ return new Enumeration(this, FHIRVersion._4_6_0, code);
+ if ("5.0".equals(codeString))
+ return new Enumeration(this, FHIRVersion._5_0, code);
+ if ("5.0.0".equals(codeString))
+ return new Enumeration(this, FHIRVersion._5_0_0, code);
+ if ("5.0.0-cibuild".equals(codeString))
+ return new Enumeration(this, FHIRVersion._5_0_0CIBUILD, code);
+ if ("5.0.0-snapshot1".equals(codeString))
+ return new Enumeration(this, FHIRVersion._5_0_0SNAPSHOT1, code);
+ if ("5.0.0-snapshot2".equals(codeString))
+ return new Enumeration(this, FHIRVersion._5_0_0SNAPSHOT2, code);
+ if ("5.0.0-ballot".equals(codeString))
+ return new Enumeration(this, FHIRVersion._5_0_0BALLOT, code);
+ if ("5.0.0-snapshot3".equals(codeString))
+ return new Enumeration(this, FHIRVersion._5_0_0SNAPSHOT3, code);
+ if ("5.0.0-draft-final".equals(codeString))
+ return new Enumeration(this, FHIRVersion._5_0_0DRAFTFINAL, code);
+ if ("6.0.0-cibuild".equals(codeString))
+ return new Enumeration(this, FHIRVersion._6_0_0CIBUILD, code);
+ if ("6.0.0".equals(codeString))
+ return new Enumeration(this, FHIRVersion._6_0_0, code);
+ if ("6.0.0-ballot1".equals(codeString))
+ return new Enumeration(this, FHIRVersion._6_0_0_BALLOT1, code);
+ if ("6.0.0-ballot2".equals(codeString))
+ return new Enumeration(this, FHIRVersion._6_0_0_BALLOT2, code);
+ throw new FHIRException("Unknown FHIRVersion code '"+codeString+"'");
+ }
public String toCode(FHIRVersion code) {
if (code == FHIRVersion.NULL)
return null;
@@ -14448,10 +14181,10 @@ public class Enumerations {
return "4.3";
if (code == FHIRVersion._4_3_0)
return "4.3.0";
- if (code == FHIRVersion._4_3_0_SNAPSHOT1)
- return "4.3.0-snapshot1";
- if (code == FHIRVersion._4_3_0_CIBUILD)
+ if (code == FHIRVersion._4_3_0CIBUILD)
return "4.3.0-cibuild";
+ if (code == FHIRVersion._4_3_0SNAPSHOT1)
+ return "4.3.0-snapshot1";
if (code == FHIRVersion._4_4)
return "4.4";
if (code == FHIRVersion._4_4_0)
@@ -14480,6 +14213,16 @@ public class Enumerations {
return "5.0.0-snapshot3";
if (code == FHIRVersion._5_0_0DRAFTFINAL)
return "5.0.0-draft-final";
+ if (code == FHIRVersion._6_0_0CIBUILD)
+ return "6.0.0-cibuild";
+ if (code == FHIRVersion._6_0_0)
+ return "6.0.0";
+ if (code == FHIRVersion._6_0_0_BALLOT1) {
+ return "6.0.0-ballot1";
+ }
+ if (code == FHIRVersion._6_0_0_BALLOT2) {
+ return "6.0.0-ballot2";
+ }
return "?";
}
diff --git a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/client/network/FhirLoggingInterceptor.java b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/client/network/FhirLoggingInterceptor.java
index 4e2e52bb9..38d195380 100644
--- a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/client/network/FhirLoggingInterceptor.java
+++ b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/client/network/FhirLoggingInterceptor.java
@@ -64,7 +64,7 @@ public class FhirLoggingInterceptor implements Interceptor {
headerMap.keySet().forEach(key -> headerMap.get(key).forEach(value -> headerList.add(key + ":" + value)));
if (logger != null) {
- logger.logResponse(Integer.toString(response.code()), headerList, bodyBytes);
+ logger.logResponse(Integer.toString(response.code()), headerList, bodyBytes, 0);
}
// Reading byte[] clears body. Need to recreate.
diff --git a/org.hl7.fhir.r4b/pom.xml b/org.hl7.fhir.r4b/pom.xml
index aec9ce8e4..9005ad3e7 100644
--- a/org.hl7.fhir.r4b/pom.xml
+++ b/org.hl7.fhir.r4b/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
org.hl7.fhir.core
- 6.3.27-SNAPSHOT
+ 6.3.30-SNAPSHOT
../pom.xml
diff --git a/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/context/HTMLClientLogger.java b/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/context/HTMLClientLogger.java
index b2e7b46bd..f19553f5e 100644
--- a/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/context/HTMLClientLogger.java
+++ b/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/context/HTMLClientLogger.java
@@ -85,7 +85,7 @@ public class HTMLClientLogger extends BaseLogger implements ToolingClientLogger
}
@Override
- public void logResponse(String outcome, List headers, byte[] body) {
+ public void logResponse(String outcome, List headers, byte[] body, long start) {
if (DEBUG) {
System.out.println(" txlog resp: " + outcome + " " + present(body));
}
diff --git a/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/context/TextClientLogger.java b/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/context/TextClientLogger.java
index 3bae5583d..fa29392ae 100644
--- a/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/context/TextClientLogger.java
+++ b/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/context/TextClientLogger.java
@@ -72,7 +72,7 @@ public class TextClientLogger extends BaseLogger implements ToolingClientLogger
}
@Override
- public void logResponse(String outcome, List headers, byte[] body) {
+ public void logResponse(String outcome, List headers, byte[] body, long start) {
if (file == null)
return;
file.println("\r\n\r\nResponse: \r\n");
diff --git a/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/utils/client/network/FhirLoggingInterceptor.java b/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/utils/client/network/FhirLoggingInterceptor.java
index 9d2f06d7b..7a9a6a282 100644
--- a/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/utils/client/network/FhirLoggingInterceptor.java
+++ b/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/utils/client/network/FhirLoggingInterceptor.java
@@ -59,7 +59,7 @@ public class FhirLoggingInterceptor implements Interceptor {
headerMap.keySet().forEach(key -> headerMap.get(key).forEach(value -> headerList.add(key + ":" + value)));
if (logger != null) {
- logger.logResponse(Integer.toString(response.code()), headerList, bodyBytes);
+ logger.logResponse(Integer.toString(response.code()), headerList, bodyBytes, 0);
}
// Reading byte[] clears body. Need to recreate.
diff --git a/org.hl7.fhir.r4b/src/test/java/org/hl7/fhir/r4b/utils/client/network/ClientTest.java b/org.hl7.fhir.r4b/src/test/java/org/hl7/fhir/r4b/utils/client/network/ClientTest.java
index 298c7e080..d9b35f263 100644
--- a/org.hl7.fhir.r4b/src/test/java/org/hl7/fhir/r4b/utils/client/network/ClientTest.java
+++ b/org.hl7.fhir.r4b/src/test/java/org/hl7/fhir/r4b/utils/client/network/ClientTest.java
@@ -134,6 +134,6 @@ class ClientTest {
server.takeRequest();
Mockito.verify(mockLogger, Mockito.times(1)).logRequest(Mockito.anyString(), Mockito.anyString(), Mockito.anyList(),
Mockito.any());
- Mockito.verify(mockLogger, Mockito.times(1)).logResponse(Mockito.anyString(), Mockito.anyList(), Mockito.any());
+ Mockito.verify(mockLogger, Mockito.times(1)).logResponse(Mockito.anyString(), Mockito.anyList(), Mockito.any(), Mockito.anyLong());
}
}
\ No newline at end of file
diff --git a/org.hl7.fhir.r5/pom.xml b/org.hl7.fhir.r5/pom.xml
index b196a2821..59d59a839 100644
--- a/org.hl7.fhir.r5/pom.xml
+++ b/org.hl7.fhir.r5/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
org.hl7.fhir.core
- 6.3.27-SNAPSHOT
+ 6.3.30-SNAPSHOT
../pom.xml
diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfileUtilities.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfileUtilities.java
index bc8d243a2..8c3f2a3e7 100644
--- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfileUtilities.java
+++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfileUtilities.java
@@ -2923,7 +2923,7 @@ public class ProfileUtilities {
private ElementDefinitionBindingAdditionalComponent getMatchingAdditionalBinding(ElementDefinitionBindingComponent nb,ElementDefinitionBindingAdditionalComponent ab) {
for (ElementDefinitionBindingAdditionalComponent t : nb.getAdditional()) {
- if (t.getValueSet() != null && t.getValueSet().equals(ab.getValueSet()) && t.getPurpose() == ab.getPurpose()) {
+ if (t.getValueSet() != null && t.getValueSet().equals(ab.getValueSet()) && t.getPurpose() == ab.getPurpose() && !ab.hasUsage()) {
return t;
}
}
@@ -4579,6 +4579,7 @@ public class ProfileUtilities {
public void setMessages(List messages) {
if (messages != null) {
this.messages = messages;
+ wantThrowExceptions = false;
}
}
diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java
index e33cc0bfa..89dde24e0 100644
--- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java
+++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java
@@ -1276,9 +1276,9 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
}
public ValidationResult validateCode(final ValidationOptions optionsArg, String path, final Coding code, final ValueSet vs, final ValidationContextCarrier ctxt) {
-
+
ValidationOptions options = optionsArg != null ? optionsArg : ValidationOptions.defaults();
-
+
if (code.hasSystem()) {
codeSystemsUsed.add(code.getSystem());
}
@@ -1303,6 +1303,9 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
// ok, first we try to validate locally
try {
ValueSetValidator vsc = constructValueSetCheckerSimple(options, vs, ctxt);
+ if (vsc.getOpContext() != null) {
+ vsc.getOpContext().note("Validate "+code.toString()+" @ "+path+" against "+(vs == null ? "null" : vs.getVersionedUrl()));
+ }
vsc.setUnknownSystems(unknownSystems);
vsc.setThrowToServer(options.isUseServer() && terminologyClientManager.hasClient());
if (!ValueSetUtilities.isServerSide(code.getSystem())) {
@@ -1471,15 +1474,15 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
}
protected ValueSetExpander constructValueSetExpanderSimple(ValidationOptions options) {
- return new ValueSetExpander(this, new TerminologyOperationContext(this, options)).setDebug(logger.isDebugLogging());
+ return new ValueSetExpander(this, new TerminologyOperationContext(this, options, "expansion")).setDebug(logger.isDebugLogging());
}
protected ValueSetValidator constructValueSetCheckerSimple(ValidationOptions options, ValueSet vs, ValidationContextCarrier ctxt) {
- return new ValueSetValidator(this, new TerminologyOperationContext(this, options), options, vs, ctxt, expParameters, terminologyClientManager);
+ return new ValueSetValidator(this, new TerminologyOperationContext(this, options, "validation"), options, vs, ctxt, expParameters, terminologyClientManager);
}
protected ValueSetValidator constructValueSetCheckerSimple( ValidationOptions options, ValueSet vs) {
- return new ValueSetValidator(this, new TerminologyOperationContext(this, options), options, vs, expParameters, terminologyClientManager);
+ return new ValueSetValidator(this, new TerminologyOperationContext(this, options, "validation"), options, vs, expParameters, terminologyClientManager);
}
protected Parameters constructParameters(TerminologyClientContext tcd, ValueSet vs, boolean hierarchical) {
@@ -1643,7 +1646,11 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
Parameters pIn = constructParameters(options, code);
res = validateOnServer(tc, vs, pIn, options);
} catch (Exception e) {
- res = new ValidationResult(IssueSeverity.ERROR, e.getMessage() == null ? e.getClass().getName() : e.getMessage(), null).setTxLink(txLog == null ? null : txLog.getLastId());
+ issues.clear();
+ OperationOutcomeIssueComponent iss = new OperationOutcomeIssueComponent(org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.ERROR, org.hl7.fhir.r5.model.OperationOutcome.IssueType.EXCEPTION);
+ iss.getDetails().setText(e.getMessage());
+ issues.add(iss);
+ res = new ValidationResult(IssueSeverity.ERROR, e.getMessage() == null ? e.getClass().getName() : e.getMessage(), issues).setTxLink(txLog == null ? null : txLog.getLastId()).setErrorClass(TerminologyServiceErrorClass.SERVER_ERROR);
}
if (cachingAllowed) {
txCache.cacheValidation(cacheToken, res, TerminologyCache.PERMANENT);
@@ -1779,6 +1786,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
if (options.isDisplayWarningMode()) {
pin.addParameter("mode","lenient-display-validation");
}
+ pin.addParameter("diagnostics", true);
}
private boolean addDependentResources(TerminologyClientContext tc, Parameters pin, ValueSet vs) {
diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/HTMLClientLogger.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/HTMLClientLogger.java
index e892ab0dc..19bd73580 100644
--- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/HTMLClientLogger.java
+++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/HTMLClientLogger.java
@@ -87,7 +87,7 @@ public class HTMLClientLogger extends BaseLogger implements ToolingClientLogger
}
@Override
- public void logResponse(String outcome, List headers, byte[] body) {
+ public void logResponse(String outcome, List headers, byte[] body, long start) {
if (DEBUG) {
System.out.println(" txlog resp: " +outcome+" "+present(body));
}
diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/TextClientLogger.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/TextClientLogger.java
index d6fc62c0f..836f528b9 100644
--- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/TextClientLogger.java
+++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/TextClientLogger.java
@@ -76,10 +76,10 @@ public class TextClientLogger extends BaseLogger implements ToolingClientLogger
}
@Override
- public void logResponse(String outcome, List headers, byte[] body) {
+ public void logResponse(String outcome, List headers, byte[] body, long length) {
if (file == null)
return;
- file.println("\r\n\r\nResponse: \r\n");
+ file.println("\r\n\r\nResponse ("+Utilities.describeDuration(length)+"): \r\n");
file.println(outcome);
for (String s : headers)
file.println(s);
diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/Element.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/Element.java
index c6254b682..fffa8164a 100644
--- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/Element.java
+++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/Element.java
@@ -162,6 +162,7 @@ public class Element extends Base implements NamedItem {
private FhirFormat format;
private Object nativeObject;
private List sliceDefinitions;
+ private boolean elided;
public Element(String name) {
super();
@@ -1429,6 +1430,8 @@ public class Element extends Base implements NamedItem {
public Base copy() {
Element element = new Element(this);
this.copyValues(element);
+ if (this.isElided())
+ element.setElided(true);
return element;
}
@@ -1638,4 +1641,11 @@ public class Element extends Base implements NamedItem {
return FhirPublication.fromCode(property.getStructure().getVersion());
}
+ public void setElided(boolean elided) {
+ this.elided = elided;
+ }
+
+ public boolean isElided() {
+ return this.elided;
+ }
}
\ No newline at end of file
diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/JsonParser.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/JsonParser.java
index a11c0c9f1..fa64c7ada 100644
--- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/JsonParser.java
+++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/JsonParser.java
@@ -62,6 +62,7 @@ import org.hl7.fhir.r5.formats.JsonCreatorDirect;
import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent;
import org.hl7.fhir.r5.model.ElementDefinition;
import org.hl7.fhir.r5.model.StructureDefinition;
+import org.hl7.fhir.r5.utils.ToolingExtensions;
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
import org.hl7.fhir.utilities.StringPair;
import org.hl7.fhir.utilities.TextFile;
@@ -85,6 +86,8 @@ public class JsonParser extends ParserBase {
private JsonCreator json;
private boolean allowComments;
+ private boolean elideElements;
+// private boolean suppressResourceType;
private Element baseElement;
private boolean markedXhtml;
@@ -782,7 +785,8 @@ public class JsonParser extends ParserBase {
}
checkComposeComments(e);
json.beginObject();
- prop("resourceType", e.getType(), null);
+// if (!isSuppressResourceType())
+ prop("resourceType", e.getType(), null);
Set done = new HashSet();
for (Element child : e.getChildren()) {
compose(e.getName(), e, done, child);
@@ -807,7 +811,8 @@ public class JsonParser extends ParserBase {
checkComposeComments(e);
json.beginObject();
- prop("resourceType", e.getType(), linkResolver == null ? null : linkResolver.resolveProperty(e.getProperty()));
+// if (!isSuppressResourceType())
+ prop("resourceType", e.getType(), linkResolver == null ? null : linkResolver.resolveProperty(e.getProperty()));
Set done = new HashSet();
for (Element child : e.getChildren()) {
compose(e.getName(), e, done, child);
@@ -821,15 +826,50 @@ public class JsonParser extends ParserBase {
if (wantCompose(path, child)) {
boolean isList = child.hasElementProperty() ? child.getElementProperty().isList() : child.getProperty().isList();
if (!isList) {// for specials, ignore the cardinality of the stated type
- compose(path, child);
+ if (child.isElided() && isElideElements() && json.canElide())
+ json.elide();
+ else
+ compose(path, child);
} else if (!done.contains(child.getName())) {
done.add(child.getName());
List list = e.getChildrenByName(child.getName());
- composeList(path, list);
+ if (child.getProperty().getDefinition().hasExtension(ToolingExtensions.EXT_JSON_PROP_KEY))
+ composeKeyList(path, list);
+ else
+ composeList(path, list);
}
}
}
+ private void composeKeyList(String path, List list) throws IOException {
+ String keyName = list.get(0).getProperty().getDefinition().getExtensionString(ToolingExtensions.EXT_JSON_PROP_KEY);
+ json.name(list.get(0).getName());
+ json.beginObject();
+ for (Element e: list) {
+ Element key = null;
+ Element value = null;
+ for (Element child: e.getChildren()) {
+ if (child.getName().equals(keyName))
+ key = child;
+ else
+ value = child;
+ }
+ if (value.isPrimitive())
+ primitiveValue(key.getValue(), value);
+ else {
+ json.name(key.getValue());
+ checkComposeComments(e);
+ json.beginObject();
+ Set done = new HashSet();
+ for (Element child : value.getChildren()) {
+ compose(value.getName(), value, done, child);
+ }
+ json.endObject();
+ compose(path + "." + key.getValue(), value);
+ }
+ }
+ json.endObject();
+ }
private void composeList(String path, List list) throws IOException {
// there will be at least one element
@@ -847,7 +887,9 @@ public class JsonParser extends ParserBase {
if (prim) {
openArray(name, linkResolver == null ? null : linkResolver.resolveProperty(list.get(0).getProperty()));
for (Element item : list) {
- if (item.hasValue()) {
+ if (item.isElided() && json.canElide())
+ json.elide();
+ else if (item.hasValue()) {
if (linkResolver != null && item.getProperty().isReference()) {
String ref = linkResolver.resolveReference(getReferenceForElement(item));
if (ref != null) {
@@ -866,7 +908,9 @@ public class JsonParser extends ParserBase {
openArray(name, linkResolver == null ? null : linkResolver.resolveProperty(list.get(0).getProperty()));
int i = 0;
for (Element item : list) {
- if (item.hasChildren()) {
+ if (item.isElided() && json.canElide())
+ json.elide();
+ else if (item.hasChildren()) {
open(null,null);
if (item.getProperty().isResource()) {
prop("resourceType", item.getType(), linkResolver == null ? null : linkResolver.resolveType(item.getType()));
@@ -933,9 +977,10 @@ public class JsonParser extends ParserBase {
json.externalLink(ref);
}
}
+
Set done = new HashSet();
for (Element child : element.getChildren()) {
- compose(path+"."+element.getName(), element, done, child);
+ compose(path + "." + element.getName(), element, done, child);
}
close();
}
@@ -951,5 +996,23 @@ public class JsonParser extends ParserBase {
return this;
}
+ public boolean isElideElements() {
+ return elideElements;
+ }
+
+ public JsonParser setElideElements(boolean elideElements) {
+ this.elideElements = elideElements;
+ return this;
+ }
+/*
+ public boolean isSuppressResourceType() {
+ return suppressResourceType;
+ }
+
+ public JsonParser setSuppressResourceType(boolean suppressResourceType) {
+ this.suppressResourceType = suppressResourceType;
+ return this;
+ }
+*/
}
\ No newline at end of file
diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/XmlParser.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/XmlParser.java
index adf06a789..4669b6095 100644
--- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/XmlParser.java
+++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/XmlParser.java
@@ -94,6 +94,7 @@ import org.xml.sax.XMLReader;
public class XmlParser extends ParserBase {
private boolean allowXsiLocation;
private String version;
+ private boolean elideElements;
public XmlParser(IWorkerContext context) {
super(context);
@@ -805,92 +806,125 @@ public class XmlParser extends ParserBase {
}
private void composeElement(IXMLWriter xml, Element element, String elementName, boolean root) throws IOException, FHIRException {
- if (showDecorations) {
- @SuppressWarnings("unchecked")
- List decorations = (List) element.getUserData("fhir.decorations");
- if (decorations != null)
- for (ElementDecoration d : decorations)
- xml.decorate(d);
- }
- for (String s : element.getComments()) {
- xml.comment(s, true);
+ if (!(isElideElements() && element.isElided())) {
+ if (showDecorations) {
+ @SuppressWarnings("unchecked")
+ List decorations = (List) element.getUserData("fhir.decorations");
+ if (decorations != null)
+ for (ElementDecoration d : decorations)
+ xml.decorate(d);
+ }
+ for (String s : element.getComments()) {
+ xml.comment(s, true);
+ }
}
if (isText(element.getProperty())) {
- if (linkResolver != null)
- xml.link(linkResolver.resolveProperty(element.getProperty()));
- xml.enter(element.getProperty().getXmlNamespace(),elementName);
- if (linkResolver != null && element.getProperty().isReference()) {
- String ref = linkResolver.resolveReference(getReferenceForElement(element));
- if (ref != null) {
- xml.externalLink(ref);
+ if (isElideElements() && element.isElided() && xml.canElide())
+ xml.elide();
+ else {
+ if (linkResolver != null)
+ xml.link(linkResolver.resolveProperty(element.getProperty()));
+ xml.enter(element.getProperty().getXmlNamespace(),elementName);
+ if (linkResolver != null && element.getProperty().isReference()) {
+ String ref = linkResolver.resolveReference(getReferenceForElement(element));
+ if (ref != null) {
+ xml.externalLink(ref);
+ }
}
+ xml.text(element.getValue());
+ xml.exit(element.getProperty().getXmlNamespace(),elementName);
}
- xml.text(element.getValue());
- xml.exit(element.getProperty().getXmlNamespace(),elementName);
} else if (!element.hasChildren() && !element.hasValue()) {
- if (element.getExplicitType() != null)
- xml.attribute("xsi:type", element.getExplicitType());
- xml.element(elementName);
+ if (isElideElements() && element.isElided() && xml.canElide())
+ xml.elide();
+ else {
+ if (element.getExplicitType() != null)
+ xml.attribute("xsi:type", element.getExplicitType());
+ xml.element(elementName);
+ }
} else if (element.isPrimitive() || (element.hasType() && isPrimitive(element.getType()))) {
if (element.getType().equals("xhtml")) {
- String rawXhtml = element.getValue();
- if (isCdaText(element.getProperty())) {
- new CDANarrativeFormat().convert(xml, new XhtmlParser().parseFragment(rawXhtml));
- } else {
- xml.escapedText(rawXhtml);
- if (!markedXhtml) {
- xml.anchor("end-xhtml");
- markedXhtml = true;
+ if (isElideElements() && element.isElided() && xml.canElide())
+ xml.elide();
+ else {
+ String rawXhtml = element.getValue();
+ if (isCdaText(element.getProperty())) {
+ new CDANarrativeFormat().convert(xml, new XhtmlParser().parseFragment(rawXhtml));
+ } else {
+ xml.escapedText(rawXhtml);
+ if (!markedXhtml) {
+ xml.anchor("end-xhtml");
+ markedXhtml = true;
+ }
}
}
} else if (isText(element.getProperty())) {
- if (linkResolver != null)
- xml.link(linkResolver.resolveProperty(element.getProperty()));
- xml.text(element.getValue());
- } else {
- setXsiTypeIfIsTypeAttr(xml, element);
- if (element.hasValue()) {
+ if (isElideElements() && element.isElided() && xml.canElide())
+ xml.elide();
+ else {
if (linkResolver != null)
- xml.link(linkResolver.resolveType(element.getType()));
- xml.attribute("value", element.getValue());
+ xml.link(linkResolver.resolveProperty(element.getProperty()));
+ xml.text(element.getValue());
}
- if (linkResolver != null)
- xml.link(linkResolver.resolveProperty(element.getProperty()));
- if (element.hasChildren()) {
- xml.enter(element.getProperty().getXmlNamespace(), elementName);
- if (linkResolver != null && element.getProperty().isReference()) {
- String ref = linkResolver.resolveReference(getReferenceForElement(element));
- if (ref != null) {
- xml.externalLink(ref);
- }
+ } else {
+ if (isElideElements() && element.isElided())
+ xml.attributeElide();
+ else {
+ setXsiTypeIfIsTypeAttr(xml, element);
+ if (element.hasValue()) {
+ if (linkResolver != null)
+ xml.link(linkResolver.resolveType(element.getType()));
+ xml.attribute("value", element.getValue());
}
- for (Element child : element.getChildren())
- composeElement(xml, child, child.getName(), false);
- xml.exit(element.getProperty().getXmlNamespace(),elementName);
- } else
- xml.element(elementName);
+ if (linkResolver != null)
+ xml.link(linkResolver.resolveProperty(element.getProperty()));
+ if (element.hasChildren()) {
+ xml.enter(element.getProperty().getXmlNamespace(), elementName);
+ if (linkResolver != null && element.getProperty().isReference()) {
+ String ref = linkResolver.resolveReference(getReferenceForElement(element));
+ if (ref != null) {
+ xml.externalLink(ref);
+ }
+ }
+ for (Element child : element.getChildren())
+ composeElement(xml, child, child.getName(), false);
+ xml.exit(element.getProperty().getXmlNamespace(),elementName);
+ } else
+ xml.element(elementName);
+ }
}
} else {
- setXsiTypeIfIsTypeAttr(xml, element);
- Set handled = new HashSet<>();
+ if (isElideElements() && element.isElided() && xml.canElide())
+ xml.elide();
+ else {
+ setXsiTypeIfIsTypeAttr(xml, element);
+ Set handled = new HashSet<>();
for (Element child : element.getChildren()) {
if (!handled.contains(child.getName()) && isAttr(child.getProperty()) && wantCompose(element.getPath(), child)) {
handled.add(child.getName());
- String av = child.getValue();
- if (child.getProperty().isList()) {
- for (Element c2 : element.getChildren()) {
- if (c2 != child && c2.getName().equals(child.getName())) {
- av = av + " "+c2.getValue();
+ if (isElideElements() && child.isElided())
+ xml.attributeElide();
+ else {
+ String av = child.getValue();
+ if (child.getProperty().isList()) {
+ for (Element c2 : element.getChildren()) {
+ if (c2 != child && c2.getName().equals(child.getName())) {
+ if (c2.isElided())
+ av = av + " ...";
+ else
+ av = av + " " + c2.getValue();
+ }
}
- }
+ }
+ if (linkResolver != null)
+ xml.link(linkResolver.resolveType(child.getType()));
+ if (ToolingExtensions.hasExtension(child.getProperty().getDefinition(), ToolingExtensions.EXT_DATE_FORMAT))
+ av = convertForDateFormatToExternal(ToolingExtensions.readStringExtension(child.getProperty().getDefinition(), ToolingExtensions.EXT_DATE_FORMAT), av);
+ xml.attribute(child.getProperty().getXmlNamespace(), child.getProperty().getXmlName(), av);
}
- if (linkResolver != null)
- xml.link(linkResolver.resolveType(child.getType()));
- if (ToolingExtensions.hasExtension(child.getProperty().getDefinition(), ToolingExtensions.EXT_DATE_FORMAT))
- av = convertForDateFormatToExternal(ToolingExtensions.readStringExtension(child.getProperty().getDefinition(), ToolingExtensions.EXT_DATE_FORMAT), av);
- xml.attribute(child.getProperty().getXmlNamespace(),child.getProperty().getXmlName(), av);
}
}
+ }
if (!element.getProperty().getDefinition().hasExtension(ToolingExtensions.EXT_ID_CHOICE_GROUP)) {
if (linkResolver != null)
xml.link(linkResolver.resolveProperty(element.getProperty()));
@@ -914,12 +948,16 @@ public class XmlParser extends ParserBase {
}
for (Element child : element.getChildren()) {
if (wantCompose(element.getPath(), child)) {
- if (isText(child.getProperty())) {
- if (linkResolver != null)
- xml.link(linkResolver.resolveProperty(element.getProperty()));
- xml.text(child.getValue());
- } else if (!isAttr(child.getProperty())) {
- composeElement(xml, child, child.getName(), false);
+ if (isElideElements() && child.isElided() && xml.canElide())
+ xml.elide();
+ else {
+ if (isText(child.getProperty())) {
+ if (linkResolver != null)
+ xml.link(linkResolver.resolveProperty(element.getProperty()));
+ xml.text(child.getValue());
+ } else if (!isAttr(child.getProperty())) {
+ composeElement(xml, child, child.getName(), false);
+ }
}
}
}
@@ -1034,4 +1072,13 @@ public class XmlParser extends ParserBase {
// do nothing
}
}
+
+ public boolean isElideElements() {
+ return elideElements;
+ }
+
+ public void setElideElements(boolean elideElements) {
+ this.elideElements = elideElements;
+ }
+
}
\ No newline at end of file
diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/formats/JsonCreator.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/formats/JsonCreator.java
index 0d4b0cf27..84c46ce0c 100644
--- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/formats/JsonCreator.java
+++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/formats/JsonCreator.java
@@ -1,5 +1,5 @@
-package org.hl7.fhir.r5.formats;
-
+package org.hl7.fhir.r5.formats;
+
/*
Copyright (c) 2011+, HL7, Inc.
All rights reserved.
@@ -28,47 +28,49 @@ package org.hl7.fhir.r5.formats;
POSSIBILITY OF SUCH DAMAGE.
*/
-
-
-
-import java.io.IOException;
-import java.math.BigDecimal;
-
-/**
- * Facade to GSON writer, or something that imposes property ordering first
- *
- * @author Grahame
- *
- */
-public interface JsonCreator {
-
- void comment(String comment);
-
- void beginObject() throws IOException;
-
- void endObject() throws IOException;
-
- void nullValue() throws IOException;
-
- void name(String name) throws IOException;
-
- void value(String value) throws IOException;
-
- void value(Boolean value) throws IOException;
-
- void value(BigDecimal value) throws IOException;
- void valueNum(String value) throws IOException; // allow full control of representation
-
- void value(Integer value) throws IOException;
-
- void beginArray() throws IOException;
-
- void endArray() throws IOException;
-
- void finish() throws IOException;
-
- // only used by an creator that actually produces xhtml
- void link(String href);
- void anchor(String string);
- void externalLink(String string);
+
+
+
+import java.io.IOException;
+import java.math.BigDecimal;
+
+/**
+ * Facade to GSON writer, or something that imposes property ordering first
+ *
+ * @author Grahame
+ *
+ */
+public interface JsonCreator {
+
+ void comment(String comment);
+
+ void beginObject() throws IOException;
+
+ void endObject() throws IOException;
+
+ void nullValue() throws IOException;
+
+ void name(String name) throws IOException;
+
+ void value(String value) throws IOException;
+
+ void value(Boolean value) throws IOException;
+
+ void value(BigDecimal value) throws IOException;
+ void valueNum(String value) throws IOException; // allow full control of representation
+
+ void value(Integer value) throws IOException;
+
+ void beginArray() throws IOException;
+
+ void endArray() throws IOException;
+
+ void finish() throws IOException;
+
+ // only used by an creator that actually produces xhtml
+ void link(String href);
+ void anchor(String string);
+ void externalLink(String string);
+ void elide();
+ boolean canElide();
}
\ No newline at end of file
diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/formats/JsonCreatorCanonical.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/formats/JsonCreatorCanonical.java
index 66acfeff6..426e9cb0e 100644
--- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/formats/JsonCreatorCanonical.java
+++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/formats/JsonCreatorCanonical.java
@@ -1,5 +1,5 @@
-package org.hl7.fhir.r5.formats;
-
+package org.hl7.fhir.r5.formats;
+
/*
Copyright (c) 2011+, HL7, Inc.
All rights reserved.
@@ -28,257 +28,264 @@ package org.hl7.fhir.r5.formats;
POSSIBILITY OF SUCH DAMAGE.
*/
-
-
-
-import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.math.BigDecimal;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Stack;
-
-public class JsonCreatorCanonical implements JsonCreator {
-
- public class JsonCanValue {
- String name;
- private JsonCanValue(String name) {
- this.name = name;
- }
- }
-
- private class JsonCanNumberValue extends JsonCanValue {
- private BigDecimal value;
- private JsonCanNumberValue(String name, BigDecimal value) {
- super(name);
- this.value = value;
- }
- }
-
- private class JsonCanPresentedNumberValue extends JsonCanValue {
- private String value;
- private JsonCanPresentedNumberValue(String name, String value) {
- super(name);
- this.value = value;
- }
- }
-
- private class JsonCanIntegerValue extends JsonCanValue {
- private Integer value;
- private JsonCanIntegerValue(String name, Integer value) {
- super(name);
- this.value = value;
- }
- }
-
- private class JsonCanBooleanValue extends JsonCanValue {
- private Boolean value;
- private JsonCanBooleanValue(String name, Boolean value) {
- super(name);
- this.value = value;
- }
- }
-
- private class JsonCanStringValue extends JsonCanValue {
- private String value;
- private JsonCanStringValue(String name, String value) {
- super(name);
- this.value = value;
- }
- }
-
- private class JsonCanNullValue extends JsonCanValue {
- private JsonCanNullValue(String name) {
- super(name);
- }
- }
-
- public class JsonCanObject extends JsonCanValue {
-
- boolean array;
- List children = new ArrayList();
-
- public JsonCanObject(String name, boolean array) {
- super(name);
- this.array = array;
- }
-
- public void addProp(JsonCanValue obj) {
- children.add(obj);
- }
- }
-
- Stack stack;
- JsonCanObject root;
- JsonCreatorDirect jj;
- String name;
-
- public JsonCreatorCanonical(OutputStreamWriter osw) {
- stack = new Stack();
- jj = new JsonCreatorDirect(osw, false, false);
- name = null;
- }
-
- private String takeName() {
- String res = name;
- name = null;
- return res;
- }
-
- @Override
- public void beginObject() throws IOException {
- JsonCanObject obj = new JsonCanObject(takeName(), false);
- if (stack.isEmpty())
- root = obj;
- else
- stack.peek().addProp(obj);
- stack.push(obj);
- }
-
- @Override
- public void endObject() throws IOException {
- stack.pop();
- }
-
- @Override
- public void nullValue() throws IOException {
- stack.peek().addProp(new JsonCanNullValue(takeName()));
- }
-
- @Override
- public void name(String name) throws IOException {
- this.name = name;
- }
-
- @Override
- public void value(String value) throws IOException {
- stack.peek().addProp(new JsonCanStringValue(takeName(), value));
- }
-
- @Override
- public void value(Boolean value) throws IOException {
- stack.peek().addProp(new JsonCanBooleanValue(takeName(), value));
- }
-
- @Override
- public void value(BigDecimal value) throws IOException {
- stack.peek().addProp(new JsonCanNumberValue(takeName(), value));
- }
- @Override
- public void valueNum(String value) throws IOException {
- stack.peek().addProp(new JsonCanPresentedNumberValue(takeName(), value));
- }
-
-
- @Override
- public void value(Integer value) throws IOException {
- stack.peek().addProp(new JsonCanIntegerValue(takeName(), value));
- }
-
- @Override
- public void beginArray() throws IOException {
- JsonCanObject obj = new JsonCanObject(takeName(), true);
- if (!stack.isEmpty())
- stack.peek().addProp(obj);
- stack.push(obj);
-
- }
-
- @Override
- public void endArray() throws IOException {
- stack.pop();
- }
-
- @Override
- public void finish() throws IOException {
- writeObject(root);
- }
-
- private void writeObject(JsonCanObject obj) throws IOException {
- jj.beginObject();
- List names = new ArrayList();
- for (JsonCanValue v : obj.children)
- names.add(v.name);
- Collections.sort(names);
- for (String n : names) {
- jj.name(n);
- JsonCanValue v = getPropForName(n, obj.children);
- if (v instanceof JsonCanNumberValue)
- jj.value(((JsonCanNumberValue) v).value);
- else if (v instanceof JsonCanPresentedNumberValue)
- jj.valueNum(((JsonCanPresentedNumberValue) v).value);
- else if (v instanceof JsonCanIntegerValue)
- jj.value(((JsonCanIntegerValue) v).value);
- else if (v instanceof JsonCanBooleanValue)
- jj.value(((JsonCanBooleanValue) v).value);
- else if (v instanceof JsonCanStringValue)
- jj.value(((JsonCanStringValue) v).value);
- else if (v instanceof JsonCanNullValue)
- jj.nullValue();
- else if (v instanceof JsonCanObject) {
- JsonCanObject o = (JsonCanObject) v;
- if (o.array)
- writeArray(o);
- else
- writeObject(o);
- } else
- throw new Error("not possible");
- }
- jj.endObject();
- }
-
- private JsonCanValue getPropForName(String name, List children) {
- for (JsonCanValue child : children)
- if (child.name.equals(name))
- return child;
- return null;
- }
-
- private void writeArray(JsonCanObject arr) throws IOException {
- jj.beginArray();
- for (JsonCanValue v : arr.children) {
- if (v instanceof JsonCanNumberValue)
- jj.value(((JsonCanNumberValue) v).value);
- else if (v instanceof JsonCanIntegerValue)
- jj.value(((JsonCanIntegerValue) v).value);
- else if (v instanceof JsonCanBooleanValue)
- jj.value(((JsonCanBooleanValue) v).value);
- else if (v instanceof JsonCanStringValue)
- jj.value(((JsonCanStringValue) v).value);
- else if (v instanceof JsonCanNullValue)
- jj.nullValue();
- else if (v instanceof JsonCanObject) {
- JsonCanObject o = (JsonCanObject) v;
- if (o.array)
- writeArray(o);
- else
- writeObject(o);
- } else
- throw new Error("not possible");
- }
- jj.endArray();
- }
-
- @Override
- public void comment(String content) {
- // canonical JSON ignores comments
- }
-
- @Override
- public void link(String href) {
- // not used
- }
-
- @Override
- public void anchor(String name) {
- // not used
- }
-
- @Override
- public void externalLink(String string) {
- // not used
- }
-
-
+
+
+
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Stack;
+
+public class JsonCreatorCanonical implements JsonCreator {
+
+ public class JsonCanValue {
+ String name;
+ private JsonCanValue(String name) {
+ this.name = name;
+ }
+ }
+
+ private class JsonCanNumberValue extends JsonCanValue {
+ private BigDecimal value;
+ private JsonCanNumberValue(String name, BigDecimal value) {
+ super(name);
+ this.value = value;
+ }
+ }
+
+ private class JsonCanPresentedNumberValue extends JsonCanValue {
+ private String value;
+ private JsonCanPresentedNumberValue(String name, String value) {
+ super(name);
+ this.value = value;
+ }
+ }
+
+ private class JsonCanIntegerValue extends JsonCanValue {
+ private Integer value;
+ private JsonCanIntegerValue(String name, Integer value) {
+ super(name);
+ this.value = value;
+ }
+ }
+
+ private class JsonCanBooleanValue extends JsonCanValue {
+ private Boolean value;
+ private JsonCanBooleanValue(String name, Boolean value) {
+ super(name);
+ this.value = value;
+ }
+ }
+
+ private class JsonCanStringValue extends JsonCanValue {
+ private String value;
+ private JsonCanStringValue(String name, String value) {
+ super(name);
+ this.value = value;
+ }
+ }
+
+ private class JsonCanNullValue extends JsonCanValue {
+ private JsonCanNullValue(String name) {
+ super(name);
+ }
+ }
+
+ public class JsonCanObject extends JsonCanValue {
+
+ boolean array;
+ List children = new ArrayList();
+
+ public JsonCanObject(String name, boolean array) {
+ super(name);
+ this.array = array;
+ }
+
+ public void addProp(JsonCanValue obj) {
+ children.add(obj);
+ }
+ }
+
+ Stack stack;
+ JsonCanObject root;
+ JsonCreatorDirect jj;
+ String name;
+
+ public JsonCreatorCanonical(OutputStreamWriter osw) {
+ stack = new Stack();
+ jj = new JsonCreatorDirect(osw, false, false);
+ name = null;
+ }
+
+ private String takeName() {
+ String res = name;
+ name = null;
+ return res;
+ }
+
+ @Override
+ public void beginObject() throws IOException {
+ JsonCanObject obj = new JsonCanObject(takeName(), false);
+ if (stack.isEmpty())
+ root = obj;
+ else
+ stack.peek().addProp(obj);
+ stack.push(obj);
+ }
+
+ @Override
+ public void endObject() throws IOException {
+ stack.pop();
+ }
+
+ @Override
+ public void nullValue() throws IOException {
+ stack.peek().addProp(new JsonCanNullValue(takeName()));
+ }
+
+ @Override
+ public void name(String name) throws IOException {
+ this.name = name;
+ }
+
+ @Override
+ public void value(String value) throws IOException {
+ stack.peek().addProp(new JsonCanStringValue(takeName(), value));
+ }
+
+ @Override
+ public void value(Boolean value) throws IOException {
+ stack.peek().addProp(new JsonCanBooleanValue(takeName(), value));
+ }
+
+ @Override
+ public void value(BigDecimal value) throws IOException {
+ stack.peek().addProp(new JsonCanNumberValue(takeName(), value));
+ }
+ @Override
+ public void valueNum(String value) throws IOException {
+ stack.peek().addProp(new JsonCanPresentedNumberValue(takeName(), value));
+ }
+
+
+ @Override
+ public void value(Integer value) throws IOException {
+ stack.peek().addProp(new JsonCanIntegerValue(takeName(), value));
+ }
+
+ @Override
+ public void beginArray() throws IOException {
+ JsonCanObject obj = new JsonCanObject(takeName(), true);
+ if (!stack.isEmpty())
+ stack.peek().addProp(obj);
+ stack.push(obj);
+
+ }
+
+ @Override
+ public void endArray() throws IOException {
+ stack.pop();
+ }
+
+ @Override
+ public void finish() throws IOException {
+ writeObject(root);
+ }
+
+ private void writeObject(JsonCanObject obj) throws IOException {
+ jj.beginObject();
+ List names = new ArrayList();
+ for (JsonCanValue v : obj.children)
+ names.add(v.name);
+ Collections.sort(names);
+ for (String n : names) {
+ jj.name(n);
+ JsonCanValue v = getPropForName(n, obj.children);
+ if (v instanceof JsonCanNumberValue)
+ jj.value(((JsonCanNumberValue) v).value);
+ else if (v instanceof JsonCanPresentedNumberValue)
+ jj.valueNum(((JsonCanPresentedNumberValue) v).value);
+ else if (v instanceof JsonCanIntegerValue)
+ jj.value(((JsonCanIntegerValue) v).value);
+ else if (v instanceof JsonCanBooleanValue)
+ jj.value(((JsonCanBooleanValue) v).value);
+ else if (v instanceof JsonCanStringValue)
+ jj.value(((JsonCanStringValue) v).value);
+ else if (v instanceof JsonCanNullValue)
+ jj.nullValue();
+ else if (v instanceof JsonCanObject) {
+ JsonCanObject o = (JsonCanObject) v;
+ if (o.array)
+ writeArray(o);
+ else
+ writeObject(o);
+ } else
+ throw new Error("not possible");
+ }
+ jj.endObject();
+ }
+
+ private JsonCanValue getPropForName(String name, List children) {
+ for (JsonCanValue child : children)
+ if (child.name.equals(name))
+ return child;
+ return null;
+ }
+
+ private void writeArray(JsonCanObject arr) throws IOException {
+ jj.beginArray();
+ for (JsonCanValue v : arr.children) {
+ if (v instanceof JsonCanNumberValue)
+ jj.value(((JsonCanNumberValue) v).value);
+ else if (v instanceof JsonCanIntegerValue)
+ jj.value(((JsonCanIntegerValue) v).value);
+ else if (v instanceof JsonCanBooleanValue)
+ jj.value(((JsonCanBooleanValue) v).value);
+ else if (v instanceof JsonCanStringValue)
+ jj.value(((JsonCanStringValue) v).value);
+ else if (v instanceof JsonCanNullValue)
+ jj.nullValue();
+ else if (v instanceof JsonCanObject) {
+ JsonCanObject o = (JsonCanObject) v;
+ if (o.array)
+ writeArray(o);
+ else
+ writeObject(o);
+ } else
+ throw new Error("not possible");
+ }
+ jj.endArray();
+ }
+
+ @Override
+ public void comment(String content) {
+ // canonical JSON ignores comments
+ }
+
+ @Override
+ public void link(String href) {
+ // not used
+ }
+
+ @Override
+ public void anchor(String name) {
+ // not used
+ }
+
+ @Override
+ public void externalLink(String string) {
+ // not used
+ }
+
+ @Override
+ public boolean canElide() { return false; }
+
+ @Override
+ public void elide() {
+ // not used
+ }
+
}
\ No newline at end of file
diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/formats/JsonCreatorDirect.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/formats/JsonCreatorDirect.java
index 019f505e3..41ac714c9 100644
--- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/formats/JsonCreatorDirect.java
+++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/formats/JsonCreatorDirect.java
@@ -1,5 +1,5 @@
-package org.hl7.fhir.r5.formats;
-
+package org.hl7.fhir.r5.formats;
+
/*
Copyright (c) 2011+, HL7, Inc.
All rights reserved.
@@ -28,219 +28,227 @@ package org.hl7.fhir.r5.formats;
POSSIBILITY OF SUCH DAMAGE.
*/
-
-
-
-import java.io.IOException;
-import java.io.Writer;
-import java.math.BigDecimal;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.hl7.fhir.utilities.Utilities;
-
-/**
- * A little implementation of a json write to replace Gson .... because Gson screws up decimal values, and *we care*
- *
- * @author Grahame Grieve
- *
- */
-public class JsonCreatorDirect implements JsonCreator {
-
- private Writer writer;
- private boolean pretty;
- private boolean comments;
- private boolean named;
- private List valued = new ArrayList();
- private int indent;
- private List commentList = new ArrayList<>();
-
- public JsonCreatorDirect(Writer writer, boolean pretty, boolean comments) {
- super();
- this.writer = writer;
- this.pretty = pretty;
- this.comments = pretty && comments;
- }
-
- @Override
- public void comment(String content) {
- if (comments) {
- commentList.add(content);
- }
- }
-
- @Override
- public void beginObject() throws IOException {
- checkState();
- writer.write("{");
- stepIn();
- if (!valued.isEmpty()) {
- valued.set(0, true);
- }
- valued.add(0, false);
- }
-
- private void commitComments() throws IOException {
- if (comments) {
- for (String s : commentList) {
- writer.write("// ");
- writer.write(s);
- writer.write("\r\n");
- for (int i = 0; i < indent; i++) {
- writer.write(" ");
- }
- }
- commentList.clear();
- }
- }
-
-
- public void stepIn() throws IOException {
- if (pretty) {
- indent++;
- writer.write("\r\n");
- for (int i = 0; i < indent; i++) {
- writer.write(" ");
- }
- }
- }
-
- public void stepOut() throws IOException {
- if (pretty) {
- indent--;
- writer.write("\r\n");
- for (int i = 0; i < indent; i++) {
- writer.write(" ");
- }
- }
- }
-
- private void checkState() throws IOException {
- commitComments();
- if (named) {
- if (pretty)
- writer.write(" : ");
- else
- writer.write(":");
- named = false;
- }
- if (!valued.isEmpty() && valued.get(0)) {
- writer.write(",");
- if (pretty) {
- writer.write("\r\n");
- for (int i = 0; i < indent; i++) {
- writer.write(" ");
- }
- }
- valued.set(0, false);
- }
- }
-
- @Override
- public void endObject() throws IOException {
- stepOut();
- writer.write("}");
- valued.remove(0);
- }
-
- @Override
- public void nullValue() throws IOException {
- checkState();
- writer.write("null");
- valued.set(0, true);
- }
-
- @Override
- public void name(String name) throws IOException {
- checkState();
- writer.write("\""+name+"\"");
- named = true;
- }
-
- @Override
- public void value(String value) throws IOException {
- checkState();
- writer.write("\""+Utilities.escapeJson(value)+"\"");
- valued.set(0, true);
- }
-
- @Override
- public void value(Boolean value) throws IOException {
- checkState();
- if (value == null)
- writer.write("null");
- else if (value.booleanValue())
- writer.write("true");
- else
- writer.write("false");
- valued.set(0, true);
- }
-
- @Override
- public void value(BigDecimal value) throws IOException {
- checkState();
- if (value == null)
- writer.write("null");
- else
- writer.write(value.toString());
- valued.set(0, true);
- }
-
- @Override
- public void valueNum(String value) throws IOException {
- checkState();
- if (value == null)
- writer.write("null");
- else
- writer.write(value);
- valued.set(0, true);
- }
-
- @Override
- public void value(Integer value) throws IOException {
- checkState();
- if (value == null)
- writer.write("null");
- else
- writer.write(value.toString());
- valued.set(0, true);
- }
-
- @Override
- public void beginArray() throws IOException {
- checkState();
- writer.write("[");
- if (!valued.isEmpty()) {
- valued.set(0, true);
- }
- valued.add(0, false);
- }
-
- @Override
- public void endArray() throws IOException {
- writer.write("]");
- valued.remove(0);
- }
-
- @Override
- public void finish() throws IOException {
- writer.flush();
- }
-
- @Override
- public void link(String href) {
- // not used
-
- }
-
- @Override
- public void anchor(String name) {
- // not used
- }
-
-
- @Override
- public void externalLink(String string) {
- // not used
- }
+
+
+
+import java.io.IOException;
+import java.io.Writer;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.hl7.fhir.utilities.Utilities;
+
+/**
+ * A little implementation of a json write to replace Gson .... because Gson screws up decimal values, and *we care*
+ *
+ * @author Grahame Grieve
+ *
+ */
+public class JsonCreatorDirect implements JsonCreator {
+
+ private Writer writer;
+ private boolean pretty;
+ private boolean comments;
+ private boolean named;
+ private List valued = new ArrayList();
+ private int indent;
+ private List commentList = new ArrayList<>();
+
+ public JsonCreatorDirect(Writer writer, boolean pretty, boolean comments) {
+ super();
+ this.writer = writer;
+ this.pretty = pretty;
+ this.comments = pretty && comments;
+ }
+
+ @Override
+ public void comment(String content) {
+ if (comments) {
+ commentList.add(content);
+ }
+ }
+
+ @Override
+ public void beginObject() throws IOException {
+ checkState();
+ writer.write("{");
+ stepIn();
+ if (!valued.isEmpty()) {
+ valued.set(0, true);
+ }
+ valued.add(0, false);
+ }
+
+ private void commitComments() throws IOException {
+ if (comments) {
+ for (String s : commentList) {
+ writer.write("// ");
+ writer.write(s);
+ writer.write("\r\n");
+ for (int i = 0; i < indent; i++) {
+ writer.write(" ");
+ }
+ }
+ commentList.clear();
+ }
+ }
+
+
+ public void stepIn() throws IOException {
+ if (pretty) {
+ indent++;
+ writer.write("\r\n");
+ for (int i = 0; i < indent; i++) {
+ writer.write(" ");
+ }
+ }
+ }
+
+ public void stepOut() throws IOException {
+ if (pretty) {
+ indent--;
+ writer.write("\r\n");
+ for (int i = 0; i < indent; i++) {
+ writer.write(" ");
+ }
+ }
+ }
+
+ private void checkState() throws IOException {
+ commitComments();
+ if (named) {
+ if (pretty)
+ writer.write(" : ");
+ else
+ writer.write(":");
+ named = false;
+ }
+ if (!valued.isEmpty() && valued.get(0)) {
+ writer.write(",");
+ if (pretty) {
+ writer.write("\r\n");
+ for (int i = 0; i < indent; i++) {
+ writer.write(" ");
+ }
+ }
+ valued.set(0, false);
+ }
+ }
+
+ @Override
+ public void endObject() throws IOException {
+ stepOut();
+ writer.write("}");
+ valued.remove(0);
+ }
+
+ @Override
+ public void nullValue() throws IOException {
+ checkState();
+ writer.write("null");
+ valued.set(0, true);
+ }
+
+ @Override
+ public void name(String name) throws IOException {
+ checkState();
+ writer.write("\""+name+"\"");
+ named = true;
+ }
+
+ @Override
+ public void value(String value) throws IOException {
+ checkState();
+ writer.write("\""+Utilities.escapeJson(value)+"\"");
+ valued.set(0, true);
+ }
+
+ @Override
+ public void value(Boolean value) throws IOException {
+ checkState();
+ if (value == null)
+ writer.write("null");
+ else if (value.booleanValue())
+ writer.write("true");
+ else
+ writer.write("false");
+ valued.set(0, true);
+ }
+
+ @Override
+ public void value(BigDecimal value) throws IOException {
+ checkState();
+ if (value == null)
+ writer.write("null");
+ else
+ writer.write(value.toString());
+ valued.set(0, true);
+ }
+
+ @Override
+ public void valueNum(String value) throws IOException {
+ checkState();
+ if (value == null)
+ writer.write("null");
+ else
+ writer.write(value);
+ valued.set(0, true);
+ }
+
+ @Override
+ public void value(Integer value) throws IOException {
+ checkState();
+ if (value == null)
+ writer.write("null");
+ else
+ writer.write(value.toString());
+ valued.set(0, true);
+ }
+
+ @Override
+ public void beginArray() throws IOException {
+ checkState();
+ writer.write("[");
+ if (!valued.isEmpty()) {
+ valued.set(0, true);
+ }
+ valued.add(0, false);
+ }
+
+ @Override
+ public void endArray() throws IOException {
+ writer.write("]");
+ valued.remove(0);
+ }
+
+ @Override
+ public void finish() throws IOException {
+ writer.flush();
+ }
+
+ @Override
+ public void link(String href) {
+ // not used
+
+ }
+
+ @Override
+ public void anchor(String name) {
+ // not used
+ }
+
+
+ @Override
+ public void externalLink(String string) {
+ // not used
+ }
+
+ @Override
+ public boolean canElide() { return false; }
+
+ @Override
+ public void elide() {
+ // not used
+ }
}
\ No newline at end of file
diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/formats/JsonCreatorGson.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/formats/JsonCreatorGson.java
index d93669b2a..14c76b0cd 100644
--- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/formats/JsonCreatorGson.java
+++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/formats/JsonCreatorGson.java
@@ -1,5 +1,5 @@
-package org.hl7.fhir.r5.formats;
-
+package org.hl7.fhir.r5.formats;
+
/*
Copyright (c) 2011+, HL7, Inc.
All rights reserved.
@@ -28,103 +28,111 @@ package org.hl7.fhir.r5.formats;
POSSIBILITY OF SUCH DAMAGE.
*/
-
-
-
-import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.math.BigDecimal;
-
-import com.google.gson.stream.JsonWriter;
-
-public class JsonCreatorGson implements JsonCreator {
-
- JsonWriter gson;
-
- public JsonCreatorGson(OutputStreamWriter osw) {
- gson = new JsonWriter(osw);
- }
-
- @Override
- public void beginObject() throws IOException {
- gson.beginObject();
- }
-
- @Override
- public void endObject() throws IOException {
- gson.endObject();
- }
-
- @Override
- public void nullValue() throws IOException {
- gson.nullValue();
- }
-
- @Override
- public void name(String name) throws IOException {
- gson.name(name);
- }
-
- @Override
- public void value(String value) throws IOException {
- gson.value(value);
- }
-
- @Override
- public void value(Boolean value) throws IOException {
- gson.value(value);
- }
-
- @Override
- public void value(BigDecimal value) throws IOException {
- gson.value(value);
- }
-
- @Override
- public void value(Integer value) throws IOException {
- gson.value(value);
- }
-
- @Override
- public void beginArray() throws IOException {
- gson.beginArray();
- }
-
- @Override
- public void endArray() throws IOException {
- gson.endArray();
- }
-
- @Override
- public void finish() {
- // nothing to do here
-
- }
-
- @Override
- public void link(String href) {
- // not used
- }
-
- @Override
- public void valueNum(String value) throws IOException {
- value(new BigDecimal(value));
- }
-
- @Override
- public void anchor(String name) {
- // not used
- }
-
- @Override
- public void comment(String content) {
- // gson (dense json) ignores comments
- }
-
-
- @Override
- public void externalLink(String string) {
- // not used
- }
-
+
+
+
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.math.BigDecimal;
+
+import com.google.gson.stream.JsonWriter;
+
+public class JsonCreatorGson implements JsonCreator {
+
+ JsonWriter gson;
+
+ public JsonCreatorGson(OutputStreamWriter osw) {
+ gson = new JsonWriter(osw);
+ }
+
+ @Override
+ public void beginObject() throws IOException {
+ gson.beginObject();
+ }
+
+ @Override
+ public void endObject() throws IOException {
+ gson.endObject();
+ }
+
+ @Override
+ public void nullValue() throws IOException {
+ gson.nullValue();
+ }
+
+ @Override
+ public void name(String name) throws IOException {
+ gson.name(name);
+ }
+
+ @Override
+ public void value(String value) throws IOException {
+ gson.value(value);
+ }
+
+ @Override
+ public void value(Boolean value) throws IOException {
+ gson.value(value);
+ }
+
+ @Override
+ public void value(BigDecimal value) throws IOException {
+ gson.value(value);
+ }
+
+ @Override
+ public void value(Integer value) throws IOException {
+ gson.value(value);
+ }
+
+ @Override
+ public void beginArray() throws IOException {
+ gson.beginArray();
+ }
+
+ @Override
+ public void endArray() throws IOException {
+ gson.endArray();
+ }
+
+ @Override
+ public void finish() {
+ // nothing to do here
+
+ }
+
+ @Override
+ public void link(String href) {
+ // not used
+ }
+
+ @Override
+ public void valueNum(String value) throws IOException {
+ value(new BigDecimal(value));
+ }
+
+ @Override
+ public void anchor(String name) {
+ // not used
+ }
+
+ @Override
+ public void comment(String content) {
+ // gson (dense json) ignores comments
+ }
+
+
+ @Override
+ public void externalLink(String string) {
+ // not used
+ }
+
+ @Override
+ public void elide() {
+ // not used
+ }
+
+ @Override
+ public boolean canElide() { return false;}
+
}
\ No newline at end of file
diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/AdditionalBindingsRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/AdditionalBindingsRenderer.java
index a80990c4c..519489942 100644
--- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/AdditionalBindingsRenderer.java
+++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/AdditionalBindingsRenderer.java
@@ -36,7 +36,7 @@ public class AdditionalBindingsRenderer {
private String valueSet;
private String doco;
private String docoShort;
- private UsageContext usage;
+ private List usages = new ArrayList();
private boolean any = false;
private boolean isUnchanged = false;
private boolean matched = false;
@@ -72,7 +72,7 @@ public class AdditionalBindingsRenderer {
isUnchanged = isUnchanged && ((valueSet==null && compare.valueSet==null) || valueSet.equals(compare.valueSet));
isUnchanged = isUnchanged && ((doco==null && compare.doco==null) || doco.equals(compare.doco));
isUnchanged = isUnchanged && ((docoShort==null && compare.docoShort==null) || docoShort.equals(compare.docoShort));
- isUnchanged = isUnchanged && ((usage==null && compare.usage==null) || usage.equals(compare.usage));
+ isUnchanged = isUnchanged && ((usages==null && compare.usages==null) || usages.equals(compare.usages));
return isUnchanged;
}
}
@@ -174,8 +174,12 @@ public class AdditionalBindingsRenderer {
abr.purpose = ext.getExtensionString("purpose");
abr.valueSet = ext.getExtensionString("valueSet");
abr.doco = ext.getExtensionString("documentation");
- abr.docoShort = ext.getExtensionString("shortDoco");
- abr.usage = (ext.hasExtension("usage")) && ext.getExtensionByUrl("usage").hasValueUsageContext() ? ext.getExtensionByUrl("usage").getValueUsageContext() : null;
+ abr.docoShort = ext.getExtensionString("shortDoco");
+ for (Extension x : ext.getExtensionsByUrl("usage")) {
+ if (x.hasValueUsageContext()) {
+ abr.usages.add(x.getValueUsageContext());
+ }
+ }
abr.any = "any".equals(ext.getExtensionString("scope"));
abr.isUnchanged = ext.hasUserData(ProfileUtilities.UD_DERIVATION_EQUALS);
return abr;
@@ -187,7 +191,7 @@ public class AdditionalBindingsRenderer {
abr.valueSet = ab.getValueSet();
abr.doco = ab.getDocumentation();
abr.docoShort = ab.getShortDoco();
- abr.usage = ab.hasUsage() ? ab.getUsageFirstRep() : null;
+ abr.usages.addAll(ab.getUsage());
abr.any = ab.getAny();
abr.isUnchanged = ab.hasUserData(ProfileUtilities.UD_DERIVATION_EQUALS);
return abr;
@@ -220,7 +224,7 @@ public class AdditionalBindingsRenderer {
boolean any = false;
for (AdditionalBindingDetail binding : bindings) {
doco = doco || binding.getDoco(fullDoco)!=null || (binding.compare!=null && binding.compare.getDoco(fullDoco)!=null);
- usage = usage || binding.usage != null || (binding.compare!=null && binding.compare.usage!=null);
+ usage = usage || !binding.usages.isEmpty() || (binding.compare!=null && !binding.compare.usages.isEmpty());
any = any || binding.any || (binding.compare!=null && binding.compare.any);
}
@@ -283,9 +287,12 @@ public class AdditionalBindingsRenderer {
renderPurpose(purpose, binding.compare.purpose);
}
if (usage) {
- if (binding.usage != null) {
- // TODO: This isn't rendered at all yet. Ideally, we want it to render with comparison...
- new DataRenderer(context).renderBase(new RenderingStatus(), tr.td(), binding.usage);
+ if (!binding.usages.isEmpty()) {
+ XhtmlNode td = tr.td();
+ for (UsageContext uc : binding.usages) {
+ td.sep(", ");
+ new DataRenderer(context).renderBase(new RenderingStatus(), td, uc);
+ }
} else {
tr.td();
}
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 ffb441b6d..839648e4d 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
@@ -46,6 +46,7 @@ import org.hl7.fhir.r5.renderers.utils.RenderingContext.GenerationRules;
import org.hl7.fhir.r5.renderers.utils.RenderingContext.ResourceRendererMode;
import org.hl7.fhir.r5.renderers.utils.ResourceWrapper;
import org.hl7.fhir.r5.terminologies.JurisdictionUtilities;
+import org.hl7.fhir.r5.terminologies.utilities.SnomedUtilities;
import org.hl7.fhir.r5.terminologies.utilities.ValidationResult;
import org.hl7.fhir.r5.utils.ToolingExtensions;
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
@@ -1177,8 +1178,8 @@ public class DataRenderer extends Renderer implements CodeResolver {
}
private String getLinkForSystem(String system, String version) {
- if ("http://snomed.info/sct".equals(system)) {
- return "https://browser.ihtsdotools.org/";
+ if ("http://snomed.info/sct".equals(system)) {
+ return "https://browser.ihtsdotools.org/";
} else if ("http://loinc.org".equals(system)) {
return "https://loinc.org/";
} else if ("http://unitsofmeasure.org".equals(system)) {
@@ -1198,11 +1199,7 @@ public class DataRenderer extends Renderer implements CodeResolver {
protected String getLinkForCode(String system, String version, String code) {
if ("http://snomed.info/sct".equals(system)) {
- if (!Utilities.noString(code)) {
- return "http://snomed.info/id/"+code;
- } else {
- return "https://browser.ihtsdotools.org/";
- }
+ return SnomedUtilities.getSctLink(version, code, context.getContext().getExpansionParameters());
} else if ("http://loinc.org".equals(system)) {
if (!Utilities.noString(code)) {
return "https://loinc.org/"+code;
@@ -1301,7 +1298,11 @@ public class DataRenderer extends Renderer implements CodeResolver {
}
}
- protected void renderCoding(RenderingStatus status, XhtmlNode x, ResourceWrapper c) {
+ protected void renderCoding(RenderingStatus status, XhtmlNode x, ResourceWrapper c) {
+ renderCoding(status, x, c, true);
+ }
+
+ protected void renderCoding(RenderingStatus status, XhtmlNode x, ResourceWrapper c, boolean details) {
String s = "";
if (c.has("display"))
s = context.getTranslated(c.child("display"));
@@ -1311,10 +1312,13 @@ public class DataRenderer extends Renderer implements CodeResolver {
if (Utilities.noString(s))
s = c.primitiveValue("code");
- if (context.isTechnicalMode()) {
- x.addText(s+" "+context.formatPhrase(RenderingContext.DATA_REND_DETAILS_STATED, displaySystem(c.primitiveValue("system")), c.primitiveValue("code"), " = '", lookupCode(c.primitiveValue("system"), c.primitiveValue("version"), c.primitiveValue("code")), c.primitiveValue("display"), "')"));
- } else
- x.span(null, "{"+c.primitiveValue("system")+" "+c.primitiveValue("code")+"}").addText(s);
+ if (context.isTechnicalMode() && details) {
+ String d = c.primitiveValue("display") == null ? lookupCode(c.primitiveValue("system"), c.primitiveValue("version"), c.primitiveValue("code")): c.primitiveValue("display");
+ d = context.formatPhrase(d == null || d.equals(c.primitiveValue("code")) ? RenderingContext.DATA_REND_DETAILS_STATED_ND : RenderingContext.DATA_REND_DETAILS_STATED, displaySystem(c.primitiveValue("system")), c.primitiveValue("code"), d);
+ x.addText(s+" "+d);
+ } else {
+ x.span(null, "{"+c.primitiveValue("system")+" "+c.primitiveValue("code")+"}").addText(s);
+ }
}
public String displayCodeableConcept(ResourceWrapper cc) {
@@ -1860,8 +1864,8 @@ public class DataRenderer extends Renderer implements CodeResolver {
}
public void renderUsageContext(RenderingStatus status, XhtmlNode x, ResourceWrapper u) throws FHIRFormatError, DefinitionException, IOException {
- renderCoding(status, x, u.child("code"));
- x.tx(": ");
+ renderCoding(status, x, u.child("code"), false);
+ x.tx(" = ");
renderDataType(status, x, u.child("value"));
}
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 16adae09a..729e5ae42 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
@@ -51,6 +51,7 @@ import org.hl7.fhir.r5.terminologies.CodeSystemUtilities;
import org.hl7.fhir.r5.terminologies.ValueSetUtilities;
import org.hl7.fhir.r5.terminologies.expansion.ValueSetExpansionOutcome;
import org.hl7.fhir.r5.terminologies.utilities.CodingValidationRequest;
+import org.hl7.fhir.r5.terminologies.utilities.SnomedUtilities;
import org.hl7.fhir.r5.terminologies.utilities.ValidationResult;
import org.hl7.fhir.r5.utils.EOperationOutcome;
import org.hl7.fhir.r5.utils.ToolingExtensions;
@@ -825,7 +826,7 @@ public class ValueSetRenderer extends TerminologyRenderer {
}
String s = Utilities.padLeft("", '\u00A0', i*2);
td.attribute("style", "white-space:nowrap").addText(s);
- addCodeToTable(c.getAbstract(), c.getSystem(), c.getCode(), c.getDisplay(), td);
+ addCodeToTable(c.getAbstract(), c.getSystem(), c.getVersion(), c.getCode(), c.getDisplay(), td);
td = tr.td();
td.addText(c.getSystem());
td = tr.td();
@@ -863,7 +864,7 @@ public class ValueSetRenderer extends TerminologyRenderer {
first = false;
XhtmlNode span = td.span(null, mapping.comp.getRelationship().toString());
span.addText(getCharForRelationship(mapping.comp));
- addRefToCode(td, mapping.group.getTarget(), m.getLink(), mapping.comp.getCode());
+ addRefToCode(td, mapping.group.getTarget(), null, m.getLink(), mapping.comp.getCode());
if (!Utilities.noString(mapping.comp.getComment()))
td.i().tx("("+mapping.comp.getComment()+")");
}
@@ -900,13 +901,13 @@ public class ValueSetRenderer extends TerminologyRenderer {
return true;
}
- private void addCodeToTable(boolean isAbstract, String system, String code, String display, XhtmlNode td) {
+ private void addCodeToTable(boolean isAbstract, String system, String version, String code, String display, XhtmlNode td) {
CodeSystem e = getContext().getWorker().fetchCodeSystem(system);
if (e == null || (e.getContent() != org.hl7.fhir.r5.model.Enumerations.CodeSystemContentMode.COMPLETE && e.getContent() != org.hl7.fhir.r5.model.Enumerations.CodeSystemContentMode.FRAGMENT)) {
if (isAbstract)
td.i().setAttribute("title", context.formatPhrase(RenderingContext.VS_ABSTRACT_CODE_HINT)).addText(code);
else if ("http://snomed.info/sct".equals(system)) {
- td.ah(context.prefixLocalHref(sctLink(code))).addText(code);
+ td.ah(context.prefixLocalHref(SnomedUtilities.getSctLink(version, code, context.getContext().getExpansionParameters()))).addText(code);
} else if ("http://loinc.org".equals(system)) {
td.ah(context.prefixLocalHref(LoincLinker.getLinkForCode(code))).addText(code);
} else
@@ -928,15 +929,8 @@ public class ValueSetRenderer extends TerminologyRenderer {
}
}
-
- public String sctLink(String code) {
-// if (snomedEdition != null)
-// http://browser.ihtsdotools.org/?perspective=full&conceptId1=428041000124106&edition=us-edition&release=v20180301&server=https://prod-browser-exten.ihtsdotools.org/api/snomed&langRefset=900000000000509007
- return "http://snomed.info/id/"+code;
- }
-
- private void addRefToCode(XhtmlNode td, String target, String vslink, String code) {
- addCodeToTable(false, target, code, null, td);
+ private void addRefToCode(XhtmlNode td, String target, String vslink, String code, String version) {
+ addCodeToTable(false, target, version, code, null, td);
// CodeSystem cs = getContext().getWorker().fetchCodeSystem(target);
// String cslink = getCsRef(cs);
// String link = cslink != null ? cslink+"#"+cs.getId()+"-"+code : vslink+"#"+code;
@@ -1212,10 +1206,10 @@ public class ValueSetRenderer extends TerminologyRenderer {
}
addMapHeaders(addTableHeaderRowStandard(t, false, true, hasDefinition, hasComments, false, false, null, langs, designations, doDesignations), maps);
for (ConceptReferenceComponent c : inc.getConcept()) {
- renderConcept(inc, langs, doDesignations, maps, designations, definitions, t, hasComments, hasDefinition, c);
+ renderConcept(inc, langs, doDesignations, maps, designations, definitions, t, hasComments, hasDefinition, c, inc.getVersion());
}
for (Base b : VersionComparisonAnnotation.getDeleted(inc, "concept" )) {
- renderConcept(inc, langs, doDesignations, maps, designations, definitions, t, hasComments, hasDefinition, (ConceptReferenceComponent) b);
+ renderConcept(inc, langs, doDesignations, maps, designations, definitions, t, hasComments, hasDefinition, (ConceptReferenceComponent) b, inc.getVersion());
}
}
if (inc.getFilter().size() > 0) {
@@ -1312,11 +1306,11 @@ public class ValueSetRenderer extends TerminologyRenderer {
private void renderConcept(ConceptSetComponent inc, List langs, boolean doDesignations,
List maps, Map designations, Map definitions,
- XhtmlNode t, boolean hasComments, boolean hasDefinition, ConceptReferenceComponent c) {
+ XhtmlNode t, boolean hasComments, boolean hasDefinition, ConceptReferenceComponent c, String version) {
XhtmlNode tr = t.tr();
XhtmlNode td = renderStatusRow(c, t, tr);
ConceptDefinitionComponent cc = definitions == null ? null : definitions.get(c.getCode());
- addCodeToTable(false, inc.getSystem(), c.getCode(), c.hasDisplay()? c.getDisplay() : cc != null ? cc.getDisplay() : "", td);
+ addCodeToTable(false, inc.getSystem(), version, c.getCode(), c.hasDisplay()? c.getDisplay() : cc != null ? cc.getDisplay() : "", td);
td = tr.td();
if (!Utilities.noString(c.getDisplay()))
@@ -1355,7 +1349,7 @@ public class ValueSetRenderer extends TerminologyRenderer {
first = false;
XhtmlNode span = td.span(null, mapping.comp.getRelationship().toString());
span.addText(getCharForRelationship(mapping.comp));
- addRefToCode(td, mapping.group.getTarget(), m.getLink(), mapping.comp.getCode());
+ addRefToCode(td, mapping.group.getTarget(), m.getLink(), mapping.comp.getCode(), version);
if (!Utilities.noString(mapping.comp.getComment()))
td.i().tx("("+mapping.comp.getComment()+")");
}
diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/client/TerminologyClientContext.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/client/TerminologyClientContext.java
index a15139944..4d8c5d7ee 100644
--- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/client/TerminologyClientContext.java
+++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/client/TerminologyClientContext.java
@@ -51,6 +51,8 @@ public class TerminologyClientContext {
}
+ private static boolean canUseCacheId;
+
private ITerminologyClient client;
private boolean initialised = false;
private CapabilityStatement capabilitiesStatementQuick;
@@ -180,7 +182,7 @@ public class TerminologyClientContext {
txCache.cacheTerminologyCapabilities(getAddress(), txcaps);
}
}
- if (txcaps != null) {
+ if (txcaps != null && TerminologyClientContext.canUseCacheId) {
for (TerminologyCapabilitiesExpansionParameterComponent t : txcaps.getExpansion().getParameter()) {
if ("cache-id".equals(t.getName())) {
setTxCaching(true);
@@ -206,6 +208,13 @@ public class TerminologyClientContext {
public String toString() {
return client.getAddress();
}
-
+
+ public static boolean isCanUseCacheId() {
+ return canUseCacheId;
+ }
+
+ public static void setCanUseCacheId(boolean canUseCacheId) {
+ TerminologyClientContext.canUseCacheId = canUseCacheId;
+ }
}
diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/expansion/ValueSetExpander.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/expansion/ValueSetExpander.java
index 7e1cfbbf7..82fd94efd 100644
--- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/expansion/ValueSetExpander.java
+++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/expansion/ValueSetExpander.java
@@ -188,7 +188,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
private ValueSetExpansionContainsComponent addCode(WorkingContext wc, String system, String code, String display, String dispLang, ValueSetExpansionContainsComponent parent, List designations, Parameters expParams,
boolean isAbstract, boolean inactive, List filters, boolean noInactive, boolean deprecated, List vsProp,
List csProps, CodeSystem cs, List expProps, List csExtList, List vsExtList, ValueSetExpansionComponent exp) throws ETooCostly {
- opContext.deadCheck();
+ opContext.deadCheck("addCode"+code);
if (filters != null && !filters.isEmpty() && !filterContainsCode(filters, system, code, exp))
return null;
@@ -447,7 +447,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
}
private void addCodeAndDescendents(WorkingContext wc, ValueSetExpansionContainsComponent focus, ValueSetExpansionContainsComponent parent, Parameters expParams, List filters, boolean noInactive, List vsProps, ValueSet vsSrc, ValueSetExpansionComponent exp) throws FHIRException, ETooCostly {
- opContext.deadCheck();
+ opContext.deadCheck("addCodeAndDescendents");
focus.checkNoModifiers("Expansion.contains", "expanding");
ValueSetExpansionContainsComponent np = null;
for (String code : getCodesForConcept(focus, expParams)) {
@@ -497,7 +497,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
private void addCodeAndDescendents(WorkingContext wc, CodeSystem cs, String system, ConceptDefinitionComponent def, ValueSetExpansionContainsComponent parent, Parameters expParams, List filters,
ConceptDefinitionComponent exclusion, ConceptFilter filterFunc, boolean noInactive, List vsProps, List otherFilters, ValueSetExpansionComponent exp) throws FHIRException, ETooCostly {
- opContext.deadCheck();
+ opContext.deadCheck("addCodeAndDescendents");
def.checkNoModifiers("Code in Code System", "expanding");
if (exclusion != null) {
if (exclusion.getCode().equals(def.getCode()))
@@ -528,7 +528,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
private void excludeCodeAndDescendents(WorkingContext wc, CodeSystem cs, String system, ConceptDefinitionComponent def, Parameters expParams, List filters,
ConceptDefinitionComponent exclusion, ConceptFilter filterFunc, List otherFilters, ValueSetExpansionComponent exp) throws FHIRException, ETooCostly {
- opContext.deadCheck();
+ opContext.deadCheck("excludeCodeAndDescendents");
def.checkNoModifiers("Code in Code System", "expanding");
if (exclusion != null) {
if (exclusion.getCode().equals(def.getCode()))
@@ -596,7 +596,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
}
private void excludeCodes(WorkingContext wc, ConceptSetComponent exc, Parameters expParams, ValueSetExpansionComponent exp, ValueSet vs) throws FHIRException, FileNotFoundException, ETooCostly, IOException {
- opContext.deadCheck();
+ opContext.deadCheck("excludeCodes");
exc.checkNoModifiers("Compose.exclude", "expanding");
if (exc.hasSystem() && exc.getConcept().size() == 0 && exc.getFilter().size() == 0) {
wc.getExcludeSystems().add(exc.getSystem());
@@ -639,7 +639,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
}
private void excludeCodes(WorkingContext wc, ValueSetExpansionComponent expand) {
- opContext.deadCheck();
+ opContext.deadCheck("excludeCodes");
for (ValueSetExpansionContainsComponent c : expand.getContains()) {
excludeCode(wc, c.getSystem(), c.getCode());
}
@@ -959,7 +959,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
}
public void copyExpansion(WorkingContext wc,List list) {
- opContext.deadCheck();
+ opContext.deadCheck("copyExpansion");
for (ValueSetExpansionContainsComponent cc : list) {
ValueSetExpansionContainsComponent n = new ValueSet.ValueSetExpansionContainsComponent();
n.setSystem(cc.getSystem());
@@ -988,7 +988,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
private int copyImportContains(List list, ValueSetExpansionContainsComponent parent, Parameters expParams, List filter, boolean noInactive, List vsProps, ValueSet vsSrc, ValueSetExpansionComponent exp) throws FHIRException, ETooCostly {
int count = 0;
- opContext.deadCheck();
+ opContext.deadCheck("copyImportContains");
for (ValueSetExpansionContainsComponent c : list) {
c.checkNoModifiers("Imported Expansion in Code System", "expanding");
ValueSetExpansionContainsComponent np = addCode(dwc, c.getSystem(), c.getCode(), c.getDisplay(), vsSrc.getLanguage(), parent, null, expParams, c.getAbstract(), c.getInactive(),
@@ -1002,7 +1002,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
}
private void includeCodes(ConceptSetComponent inc, ValueSetExpansionComponent exp, Parameters expParams, boolean heirarchical, boolean noInactive, List extensions, ValueSet valueSet) throws ETooCostly, FileNotFoundException, IOException, FHIRException, CodeSystemProviderExtension {
- opContext.deadCheck();
+ opContext.deadCheck("includeCodes");
inc.checkNoModifiers("Compose.include", "expanding");
List imports = new ArrayList();
for (CanonicalType imp : inc.getValueSet()) {
@@ -1033,7 +1033,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
}
private void doServerIncludeCodes(ConceptSetComponent inc, boolean heirarchical, ValueSetExpansionComponent exp, List imports, Parameters expParams, List extensions, boolean noInactive, List vsProps) throws FHIRException, CodeSystemProviderExtension, ETooCostly {
- opContext.deadCheck();
+ opContext.deadCheck("doServerIncludeCodes");
CodeSystemProvider csp = CodeSystemProvider.factory(inc.getSystem());
if (csp != null) {
csp.includeCodes(inc, heirarchical, exp, imports, expParams, extensions, noInactive, vsProps);
@@ -1075,7 +1075,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
public void doInternalIncludeCodes(ConceptSetComponent inc, ValueSetExpansionComponent exp, Parameters expParams, List imports, CodeSystem cs, boolean noInactive, Resource vsSrc) throws NoTerminologyServiceException, TerminologyServiceException, FHIRException, ETooCostly {
- opContext.deadCheck();
+ opContext.deadCheck("doInternalIncludeCodes");
if (cs == null) {
if (context.isNoTerminologyServer())
throw failTSE("Unable to find code system " + inc.getSystem().toString());
@@ -1160,7 +1160,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
private void processFilter(ConceptSetComponent inc, ValueSetExpansionComponent exp, Parameters expParams, List imports, CodeSystem cs, boolean noInactive,
ConceptSetFilterComponent fc, WorkingContext wc, List filters, boolean exclude)
throws ETooCostly {
- opContext.deadCheck();
+ opContext.deadCheck("processFilter");
if ("concept".equals(fc.getProperty()) && fc.getOp() == FilterOperator.ISA) {
// special: all codes in the target code system under the value
ConceptDefinitionComponent def = getConceptForCode(cs.getConcept(), fc.getValue());
@@ -1213,7 +1213,7 @@ public class ValueSetExpander extends ValueSetProcessBase {
if (isNotBlank(def.getDisplay()) && isNotBlank(fc.getValue())) {
if (def.getDisplay().contains(fc.getValue()) && passesOtherFilters(filters, cs, def.getCode())) {
for (String code : getCodesForConcept(def, expParams)) {
- opContext.deadCheck();
+ opContext.deadCheck("processFilter2");
if (exclude) {
excludeCode(wc, inc.getSystem(), code);
} else {
diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/utilities/SnomedUtilities.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/utilities/SnomedUtilities.java
new file mode 100644
index 000000000..07f009626
--- /dev/null
+++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/utilities/SnomedUtilities.java
@@ -0,0 +1,74 @@
+package org.hl7.fhir.r5.terminologies.utilities;
+
+import org.hl7.fhir.r5.model.Parameters;
+import org.hl7.fhir.r5.model.Parameters.ParametersParameterComponent;
+import org.hl7.fhir.utilities.Utilities;
+
+
+//URL: http://snomed.info/sct/[module]/version/[e.g. 20150131]'
+//International: 900000000000207008
+//US: 731000124108
+//Australia: 32506021000036107
+//Belgium: 11000172109
+//Canada: 20611000087101
+//Spain: 449081005
+//Denmark: 554471000005108
+//Netherlands: 11000146104
+//Sweden: 45991000052106
+//Switzerland: 2011000195101
+//UK: 83821000000107
+//IPS: 827022005
+
+public class SnomedUtilities {
+
+ public static String getVersionFromParameters(Parameters p, String version) {
+ for (ParametersParameterComponent pp : p.getParameter()) {
+ switch (pp.getName()) {
+ case "system-version" :
+ if (version == null) {
+ return pp.getValue().primitiveValue();
+ }
+ case "force-system-version":
+ return pp.getValue().primitiveValue();
+ }
+ }
+ return version;
+ }
+
+ public static String getEditionFromVersion(String version) {
+ if (version == null) {
+ return null;
+ }
+ if (version.startsWith("http://snomed.info/sct/")) {
+ version = version.substring(23);
+ }
+ if (version.contains("/")) {
+ version = version.substring(0, version.indexOf("/"));
+ }
+ if (Utilities.existsInList(version, "900000000000207008", "731000124108", "32506021000036107", "11000172109", "20611000087101",
+ "449081005", "554471000005108", "11000146104", "45991000052106", "2011000195101", "83821000000107", "827022005")) {
+ return version;
+ } else {
+ return null;
+ }
+ }
+
+ public static String getSctLink(String version, String code, Parameters p) {
+ if (!Utilities.noString(code)) {
+ version = SnomedUtilities.getVersionFromParameters(p, version);
+ String edId = SnomedUtilities.getEditionFromVersion(version);
+ if (edId != null) {
+ // if there's a version that's an edition, then:
+ // http://snomed.info/sct/11000172109/id//371305003
+ return "http://snomed.info/sct/"+edId+"/id/"+code;
+ } else {
+ // no, version:
+ return "http://snomed.info/id/"+code;
+ }
+ } else {
+ return "https://browser.ihtsdotools.org/";
+ }
+ }
+}
+
+
diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/utilities/TerminologyCache.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/utilities/TerminologyCache.java
index b65c63a2e..3a60a33bc 100644
--- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/utilities/TerminologyCache.java
+++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/utilities/TerminologyCache.java
@@ -302,22 +302,26 @@ public class TerminologyCache {
this.lock = lock;
if (folder == null) {
folder = Utilities.path("[tmp]", "default-tx-cache");
+ } else if ("n/a".equals(folder)) {
+ // this is a weird way to do things but it maintains the legacy interface
+ folder = null;
}
this.folder = folder;
requestCount = 0;
hitCount = 0;
networkCount = 0;
-
- File f = ManagedFileAccess.file(folder);
- if (!f.exists()) {
- Utilities.createDirectory(folder);
+ if (folder != null) {
+ File f = ManagedFileAccess.file(folder);
+ if (!f.exists()) {
+ Utilities.createDirectory(folder);
+ }
+ if (!f.exists()) {
+ throw new IOException("Unable to create terminology cache at "+folder);
+ }
+ checkVersion();
+ load();
}
- if (!f.exists()) {
- throw new IOException("Unable to create terminology cache at "+folder);
- }
- checkVersion();
- load();
}
private void checkVersion() throws IOException {
@@ -361,7 +365,9 @@ public class TerminologyCache {
}
private void clear() throws IOException {
- Utilities.clearDirectory(folder);
+ if (folder != null) {
+ Utilities.clearDirectory(folder);
+ }
caches.clear();
vsCache.clear();
csCache.clear();
@@ -1039,7 +1045,7 @@ public class TerminologyCache {
public SourcedValueSet getValueSet(String canonical) {
SourcedValueSetEntry sp = vsCache.get(canonical);
- if (sp == null) {
+ if (sp == null || folder == null) {
return null;
} else {
try {
@@ -1052,7 +1058,7 @@ public class TerminologyCache {
public SourcedCodeSystem getCodeSystem(String canonical) {
SourcedCodeSystemEntry sp = csCache.get(canonical);
- if (sp == null) {
+ if (sp == null || folder == null) {
return null;
} else {
try {
@@ -1073,7 +1079,9 @@ public class TerminologyCache {
} else {
String uuid = Utilities.makeUuidLC();
String fn = "vs-"+uuid+".json";
- new JsonParser().compose(ManagedFileAccess.outStream(Utilities.path(folder, fn)), svs.getVs());
+ if (folder != null) {
+ new JsonParser().compose(ManagedFileAccess.outStream(Utilities.path(folder, fn)), svs.getVs());
+ }
vsCache.put(canonical, new SourcedValueSetEntry(svs.getServer(), fn));
}
org.hl7.fhir.utilities.json.model.JsonObject j = new org.hl7.fhir.utilities.json.model.JsonObject();
@@ -1090,7 +1098,9 @@ public class TerminologyCache {
j.add(k, e);
}
}
- org.hl7.fhir.utilities.json.parser.JsonParser.compose(j, ManagedFileAccess.file(Utilities.path(folder, "vs-externals.json")), true);
+ if (folder != null) {
+ org.hl7.fhir.utilities.json.parser.JsonParser.compose(j, ManagedFileAccess.file(Utilities.path(folder, "vs-externals.json")), true);
+ }
} catch (Exception e) {
e.printStackTrace();
}
@@ -1106,7 +1116,9 @@ public class TerminologyCache {
} else {
String uuid = Utilities.makeUuidLC();
String fn = "cs-"+uuid+".json";
- new JsonParser().compose(ManagedFileAccess.outStream(Utilities.path(folder, fn)), scs.getCs());
+ if (folder != null) {
+ new JsonParser().compose(ManagedFileAccess.outStream(Utilities.path(folder, fn)), scs.getCs());
+ }
csCache.put(canonical, new SourcedCodeSystemEntry(scs.getServer(), fn));
}
org.hl7.fhir.utilities.json.model.JsonObject j = new org.hl7.fhir.utilities.json.model.JsonObject();
@@ -1123,7 +1135,9 @@ public class TerminologyCache {
j.add(k, e);
}
}
- org.hl7.fhir.utilities.json.parser.JsonParser.compose(j, ManagedFileAccess.file(Utilities.path(folder, "cs-externals.json")), true);
+ if (folder != null) {
+ org.hl7.fhir.utilities.json.parser.JsonParser.compose(j, ManagedFileAccess.file(Utilities.path(folder, "cs-externals.json")), true);
+ }
} catch (Exception e) {
e.printStackTrace();
}
diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/utilities/TerminologyOperationContext.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/utilities/TerminologyOperationContext.java
index a9632ede9..5ac1cd591 100644
--- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/utilities/TerminologyOperationContext.java
+++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/utilities/TerminologyOperationContext.java
@@ -7,6 +7,7 @@ import org.hl7.fhir.exceptions.TerminologyServiceException;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.model.OperationOutcome.IssueType;
import org.hl7.fhir.r5.terminologies.utilities.TerminologyOperationContext.TerminologyServiceProtectionException;
+import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.i18n.I18nConstants;
import org.hl7.fhir.utilities.validation.ValidationOptions;
@@ -38,16 +39,22 @@ public class TerminologyOperationContext {
public static boolean debugging = java.lang.management.ManagementFactory.getRuntimeMXBean().getInputArguments().toString().indexOf("-agentlib:jdwp") > 0;
private static final int EXPANSION_DEAD_TIME_SECS = 60;
private long deadTime;
+ private int nestCount = 0;
+ private long startTime;
private List contexts = new ArrayList<>();
private IWorkerContext worker;
private boolean original;
private ValidationOptions options;
+ private String name;
+ private List notes = new ArrayList<>();
- public TerminologyOperationContext(IWorkerContext worker, ValidationOptions options) {
+ public TerminologyOperationContext(IWorkerContext worker, ValidationOptions options, String name) {
super();
this.worker = worker;
this.original = true;
this.options = options;
+ this.name = name;
+ this.startTime = System.currentTimeMillis();
if (EXPANSION_DEAD_TIME_SECS == 0 || debugging) {
deadTime = 0;
@@ -56,22 +63,33 @@ public class TerminologyOperationContext {
}
}
- private TerminologyOperationContext(ValidationOptions options) {
+ private TerminologyOperationContext(ValidationOptions options, String name) {
super();
this.options = options;
+ this.name = name;
+ this.startTime = System.currentTimeMillis();
}
public TerminologyOperationContext copy() {
- TerminologyOperationContext ret = new TerminologyOperationContext(this.options);
+ TerminologyOperationContext ret = new TerminologyOperationContext(this.options, name);
ret.worker = worker;
ret.contexts.addAll(contexts);
ret.deadTime = deadTime;
+ ret.notes = notes;
+ ret.startTime = startTime;
+ ret.nestCount = nestCount + 1;
return ret;
}
- public void deadCheck() {
+ public void deadCheck(String note) {
+ note(note);
if (deadTime != 0 && System.currentTimeMillis() > deadTime) {
- throw new TerminologyServiceProtectionException(worker.formatMessage(I18nConstants.VALUESET_TOO_COSTLY_TIME, contexts.get(0), EXPANSION_DEAD_TIME_SECS), TerminologyServiceErrorClass.TOO_COSTLY, IssueType.TOOCOSTLY);
+ System.out.println();
+ System.out.println("Operation took too long - longer than "+(deadTime - startTime)+"ms");
+ for (String s : notes) {
+ System.out.println(s);
+ }
+ throw new TerminologyServiceProtectionException(worker.formatMessage(I18nConstants.VALUESET_TOO_COSTLY_TIME, contexts.get(0), EXPANSION_DEAD_TIME_SECS, name+" (local)"), TerminologyServiceErrorClass.TOO_COSTLY, IssueType.TOOCOSTLY);
}
}
@@ -90,5 +108,8 @@ public class TerminologyOperationContext {
return options;
}
-
+ public void note(String s) {
+ s = Utilities.padLeft("", ' ', nestCount)+" "+(System.currentTimeMillis() - startTime)+" "+s;
+ notes.add(s);
+ }
}
diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/utilities/ValueSetProcessBase.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/utilities/ValueSetProcessBase.java
index a547327d5..406127929 100644
--- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/utilities/ValueSetProcessBase.java
+++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/utilities/ValueSetProcessBase.java
@@ -49,7 +49,7 @@ public class ValueSetProcessBase {
protected IWorkerContext context;
protected TerminologyOperationContext opContext;
protected List requiredSupplements = new ArrayList<>();
-
+
protected ValueSetProcessBase(IWorkerContext context, TerminologyOperationContext opContext) {
super();
this.context = context;
@@ -229,7 +229,11 @@ public class ValueSetProcessBase {
}
}
}
-
+
+ public TerminologyOperationContext getOpContext() {
+ return opContext;
+ }
+
protected AlternateCodesProcessingRules altCodeParams = new AlternateCodesProcessingRules(false);
protected AlternateCodesProcessingRules allAltCodes = new AlternateCodesProcessingRules(true);
diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/validation/ValueSetValidator.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/validation/ValueSetValidator.java
index dd8b9733a..44e55cbc8 100644
--- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/validation/ValueSetValidator.java
+++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/validation/ValueSetValidator.java
@@ -175,11 +175,15 @@ public class ValueSetValidator extends ValueSetProcessBase {
}
private void analyseValueSet() {
+ opContext.note("analyse");
if (valueset != null) {
+ opContext.note("vs = "+valueset.getVersionedUrl());
opContext.seeContext(valueset.getVersionedUrl());
for (Extension s : valueset.getExtensionsByUrl(ExtensionConstants.EXT_VSSUPPLEMENT)) {
requiredSupplements.add(s.getValue().primitiveValue());
}
+ } else {
+ opContext.note("vs = null");
}
altCodeParams.seeParameters(expansionProfile);
@@ -187,17 +191,18 @@ public class ValueSetValidator extends ValueSetProcessBase {
if (localContext != null) {
if (valueset != null) {
for (ConceptSetComponent i : valueset.getCompose().getInclude()) {
- analyseComponent(i);
+ analyseComponent(i, "inc"+i);
}
for (ConceptSetComponent i : valueset.getCompose().getExclude()) {
- analyseComponent(i);
+ analyseComponent(i, "exc"+i);
}
}
}
+ opContext.note("analysed");
}
- private void analyseComponent(ConceptSetComponent i) {
- opContext.deadCheck();
+ private void analyseComponent(ConceptSetComponent i, String name) {
+ opContext.deadCheck("analyse Component "+name);
if (i.getSystemElement().hasExtension(ToolingExtensions.EXT_VALUESET_SYSTEM)) {
String ref = i.getSystemElement().getExtensionString(ToolingExtensions.EXT_VALUESET_SYSTEM);
if (ref.startsWith("#")) {
@@ -219,11 +224,15 @@ public class ValueSetValidator extends ValueSetProcessBase {
}
public ValidationResult validateCode(String path, CodeableConcept code) throws FHIRException {
- opContext.deadCheck();
+ opContext.deadCheck("validate "+code.toString());
checkValueSetOptions();
// first, we validate the codings themselves
ValidationProcessInfo info = new ValidationProcessInfo();
+
+ if (throwToServer) {
+ checkValueSetLoad(info);
+ }
CodeableConcept vcc = new CodeableConcept();
List resList = new ArrayList<>();
@@ -395,6 +404,45 @@ public class ValueSetValidator extends ValueSetProcessBase {
}
}
+ private void checkValueSetLoad(ValidationProcessInfo info) {
+ int serverCount = getServerLoad(info);
+ // There's a trade off here: if we're going to hit the server inside the components, then
+ // the amount of value set collateral we send is limited, but we pay the price of hitting
+ // the server multiple times. If, on the other hand, we give up on that, and hit the server
+ // directly, we have to send value set collateral (though we cache at the higher level)
+ //
+ // the cutoff value is chosen experimentally
+ if (serverCount > 2) {
+ throw new VSCheckerException("This value set is better processed on the server for performance reasons", null, true);
+ }
+ }
+
+ private int getServerLoad(ValidationProcessInfo info) {
+ int serverCount = 0;
+ if (valueset != null) {
+ for (ConceptSetComponent inc : valueset.getCompose().getInclude()) {
+ serverCount = serverCount + checkValueSetLoad(inc, info);
+ }
+ for (ConceptSetComponent inc : valueset.getCompose().getExclude()) {
+ serverCount = serverCount + checkValueSetLoad(inc, info);
+ }
+ }
+ return serverCount;
+ }
+
+ private int checkValueSetLoad(ConceptSetComponent inc, ValidationProcessInfo info) {
+ int serverCount = 0;
+ for (UriType uri : inc.getValueSet()) {
+ ValueSetValidator vsv = getVs(uri.getValue(), info);
+ serverCount += vsv.getServerLoad(info);
+ }
+ CodeSystem cs = resolveCodeSystem(inc.getSystem(), inc.getVersion());
+ if (cs == null || (cs.getContent() != CodeSystemContentMode.COMPLETE && cs.getContent() != CodeSystemContentMode.FRAGMENT)) {
+ serverCount++;
+ }
+ return serverCount;
+ }
+
private boolean checkRequiredSupplements(ValidationProcessInfo info) {
if (!requiredSupplements.isEmpty()) {
String msg= context.formatMessagePlural(requiredSupplements.size(), I18nConstants.VALUESET_SUPPLEMENT_MISSING, CommaSeparatedStringBuilder.build(requiredSupplements));
@@ -466,7 +514,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
}
public ValidationResult validateCode(String path, Coding code) throws FHIRException {
- opContext.deadCheck();
+ opContext.deadCheck("validate "+code.toString());
checkValueSetOptions();
String warningMessage = null;
@@ -798,7 +846,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
private ValidationResult findCodeInExpansion(Coding code, List contains) {
for (ValueSetExpansionContainsComponent containsComponent: contains) {
- opContext.deadCheck();
+ opContext.deadCheck("findCodeInExpansion");
if (containsComponent.getSystem().equals(code.getSystem()) && containsComponent.getCode().equals(code.getCode())) {
ConceptDefinitionComponent ccd = new ConceptDefinitionComponent();
ccd.setCode(containsComponent.getCode());
@@ -825,7 +873,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
private boolean checkExpansion(Coding code, List contains, VersionInfo vi) {
for (ValueSetExpansionContainsComponent containsComponent: contains) {
- opContext.deadCheck();
+ opContext.deadCheck("checkExpansion: "+code.toString());
if (containsComponent.hasSystem() && containsComponent.hasCode() && containsComponent.getSystem().equals(code.getSystem()) && containsComponent.getCode().equals(code.getCode())) {
vi.setExpansionVersion(containsComponent.getVersion());
return true;
@@ -882,7 +930,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
}
for (ConceptDefinitionDesignationComponent ds : cc.getDesignation()) {
- opContext.deadCheck();
+ opContext.deadCheck("validateCode1 "+ds.toString());
if (isOkLanguage(ds.getLanguage())) {
b.append("'"+ds.getValue()+"' ("+ds.getLanguage()+")");
if (code.getDisplay().equalsIgnoreCase(ds.getValue())) {
@@ -904,7 +952,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
}
}
for (ConceptReferenceDesignationComponent ds : vs.getCc().getDesignation()) {
- opContext.deadCheck();
+ opContext.deadCheck("validateCode2 "+ds.toString());
if (isOkLanguage(ds.getLanguage())) {
b.append("'"+ds.getValue()+"'");
if (code.getDisplay().equalsIgnoreCase(ds.getValue())) {
@@ -1009,7 +1057,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
return null;
// if it has an expansion
for (ValueSetExpansionContainsComponent exp : valueset.getExpansion().getContains()) {
- opContext.deadCheck();
+ opContext.deadCheck("findValueSetRef "+exp.toString());
if (system.equals(exp.getSystem()) && code.equals(exp.getCode())) {
ConceptReferenceComponent cc = new ConceptReferenceComponent();
cc.setDisplay(exp.getDisplay());
@@ -1048,7 +1096,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
}
private ConceptDefinitionComponent findCodeInConcept(ConceptDefinitionComponent concept, String code, boolean caseSensitive, AlternateCodesProcessingRules altCodeRules) {
- opContext.deadCheck();
+ opContext.deadCheck("findCodeInConcept: "+code.toString()+", "+concept.toString());
if (code.equals(concept.getCode())) {
return concept;
}
@@ -1121,7 +1169,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
int i = 0;
for (ConceptSetComponent vsi : valueset.getCompose().getInclude()) {
- opContext.deadCheck();
+ opContext.deadCheck("scanForCodeInValueSet: "+code.toString());
if (scanForCodeInValueSetInclude(code, sys, problems, i, vsi)) {
return true;
}
@@ -1241,7 +1289,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
*/
private boolean checkSystems(List contains, String code, Set systems, List problems) {
for (ValueSetExpansionContainsComponent c: contains) {
- opContext.deadCheck();
+ opContext.deadCheck("checkSystems "+code.toString());
if (c.getCode().equals(code)) {
systems.add(c.getSystem());
}
@@ -1255,7 +1303,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
if (valueset == null) {
return null;
}
- opContext.deadCheck();
+ opContext.deadCheck("codeInValueSet: "+system+"#"+code);
checkCanonical(info.getIssues(), path, valueset, valueset);
Boolean result = false;
VersionInfo vi = new VersionInfo(this);
@@ -1290,7 +1338,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
}
private Boolean inComponent(String path, ConceptSetComponent vsi, int vsiIndex, String system, String version, String code, boolean only, ValidationProcessInfo info) throws FHIRException {
- opContext.deadCheck();
+ opContext.deadCheck("inComponent "+vsiIndex);
boolean ok = true;
if (vsi.hasValueSet()) {
@@ -1339,6 +1387,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
vs.setUrl(valueset.getUrl()+"--"+vsiIndex);
vs.setVersion(valueset.getVersion());
vs.getCompose().addInclude(vsi);
+ opContext.deadCheck("hit server "+vs.getVersionedUrl());
ValidationResult res = context.validateCode(options.withNoClient(), new Coding(system, code, null), vs);
if (res.getErrorClass() == TerminologyServiceErrorClass.UNKNOWN || res.getErrorClass() == TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED || res.getErrorClass() == TerminologyServiceErrorClass.VALUESET_UNSUPPORTED) {
if (info != null && res.getErrorClass() == TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED) {
@@ -1348,16 +1397,20 @@ public class ValueSetValidator extends ValueSetProcessBase {
info.addIssue(makeIssue(IssueSeverity.WARNING, IssueType.UNKNOWN, path, msg, OpIssueCode.NotFound, null));
for (ConceptReferenceComponent cc : vsi.getConcept()) {
if (cc.getCode().equals(code)) {
+ opContext.deadCheck("server true");
return true;
}
}
}
info.setErr(TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED);
+ opContext.deadCheck("server codesystem unsupported");
return null;
}
+ opContext.deadCheck("server not found");
return false;
}
if (res.getErrorClass() == TerminologyServiceErrorClass.NOSERVICE) {
+ opContext.deadCheck("server no server");
throw new NoTerminologyServiceException();
}
return res.isOk();
@@ -1538,7 +1591,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
}
public boolean validateCodeInConceptList(String code, CodeSystem def, List list, AlternateCodesProcessingRules altCodeRules) {
- opContext.deadCheck();
+ opContext.deadCheck("validateCodeInConceptList");
if (def.hasUserData("tx.cs.special")) {
return ((SpecialCodeSystem) def.getUserData("tx.cs.special")).findConcept(new Coding().setCode(code)) != null;
} else if (def.getCaseSensitive()) {
@@ -1580,7 +1633,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
inner.put(url, vsc);
return vsc;
}
-
+
private Boolean inImport(String path, String uri, String system, String version, String code, ValidationProcessInfo info) throws FHIRException {
ValueSetValidator vs = getVs(uri, info);
if (vs == null) {
diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/PackageHackerR5.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/PackageHackerR5.java
index 5ea179634..376afc72b 100644
--- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/PackageHackerR5.java
+++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/PackageHackerR5.java
@@ -36,6 +36,10 @@ public class PackageHackerR5 {
r.hack("http://terminology.hl7.org/CodeSystem/v2-0360-2.3.1", "2.3.1");
}
+ if ("http://hl7.org/fhir/ValueSet/languages".equals(r.getUrl())) {
+ r.getResource().setExperimental(false);
+ }
+
if ("http://hl7.org/fhir/StructureDefinition/iso21090-nullFlavor".equals(r.getUrl()) && "4.0.1".equals(r.getVersion())) {
StructureDefinition sd = (StructureDefinition) r.getResource();
for (ElementDefinition ed : sd.getSnapshot().getElement()) {
diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/client/network/FhirLoggingInterceptor.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/client/network/FhirLoggingInterceptor.java
index ac7bf4a94..1314e6c8a 100644
--- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/client/network/FhirLoggingInterceptor.java
+++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/client/network/FhirLoggingInterceptor.java
@@ -59,7 +59,8 @@ public class FhirLoggingInterceptor implements Interceptor {
headerMap.keySet().forEach(key -> headerMap.get(key).forEach(value -> headerList.add(key + ":" + value)));
if (logger != null) {
- logger.logResponse(Integer.toString(response.code()), headerList, bodyBytes);
+ long responseTimeInMillis = response.receivedResponseAtMillis() - response.sentRequestAtMillis();
+ logger.logResponse(Integer.toString(response.code()), headerList, bodyBytes, responseTimeInMillis);
}
// Reading byte[] clears body. Need to recreate.
diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/formats/XmlLocationAnnotator.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/formats/XmlLocationAnnotator.java
index 0a751ee2c..84d4ed31d 100644
--- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/formats/XmlLocationAnnotator.java
+++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/formats/XmlLocationAnnotator.java
@@ -44,6 +44,8 @@ import org.w3c.dom.events.MutationEvent;
import org.xml.sax.Attributes;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
+import org.xml.sax.SAXNotRecognizedException;
+import org.xml.sax.SAXNotSupportedException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.LocatorImpl;
import org.xml.sax.helpers.XMLFilterImpl;
@@ -71,6 +73,22 @@ public class XmlLocationAnnotator extends XMLFilterImpl {
((EventTarget) dom).addEventListener("DOMNodeInserted", modListener, true);
}
+ @Override
+ public void setProperty(String name, Object value) throws SAXNotRecognizedException, SAXNotSupportedException {
+ if (!name.equals("http://javax.xml.XMLConstants/property/accessExternalDTD")) {
+ super.setProperty(name, value);
+ }
+ }
+
+ @Override
+ public Object getProperty(String name) throws SAXNotRecognizedException, SAXNotSupportedException {
+ if (!name.equals("http://javax.xml.XMLConstants/property/accessExternalDTD")) {
+ return null;
+ } else {
+ return super.getProperty(name);
+ }
+ }
+
@Override
public void setDocumentLocator(Locator locator) {
super.setDocumentLocator(locator);
diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/context/BaseWorkerContextTests.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/context/BaseWorkerContextTests.java
index 9d646387b..8c6e41fa0 100644
--- a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/context/BaseWorkerContextTests.java
+++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/context/BaseWorkerContextTests.java
@@ -13,6 +13,7 @@ import org.hl7.fhir.r5.utils.validation.IResourceValidator;
import org.hl7.fhir.r5.utils.validation.ValidationContextCarrier;
import org.hl7.fhir.utilities.FhirPublication;
import org.hl7.fhir.utilities.ToolingClientLogger;
+import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.npm.BasePackageCacheManager;
import org.hl7.fhir.utilities.npm.NpmPackage;
import org.hl7.fhir.utilities.validation.ValidationMessage;
@@ -341,6 +342,7 @@ public class BaseWorkerContextTests {
public void testValidateCodingWithValueSetChecker() throws IOException {
ValidationOptions validationOptions = new ValidationOptions(FhirPublication.R5).withGuessSystem().withVersionFlexible(false);
ValueSet valueSet = new ValueSet();
+ valueSet.setUrl(Utilities.makeUuidUrn());
Coding coding = new Coding();
Mockito.doReturn(cacheToken).when(terminologyCache).generateValidationToken(validationOptions, coding, valueSet, expParameters);
diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/utils/client/network/ClientTest.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/utils/client/network/ClientTest.java
index fe1e94411..de6aa7f8f 100644
--- a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/utils/client/network/ClientTest.java
+++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/utils/client/network/ClientTest.java
@@ -172,6 +172,6 @@ class ClientTest {
Mockito.verify(mockLogger, Mockito.times(1))
.logRequest(Mockito.anyString(), Mockito.anyString(), Mockito.anyList(), Mockito.any());
Mockito.verify(mockLogger, Mockito.times(1))
- .logResponse(Mockito.anyString(), Mockito.anyList(), Mockito.any());
+ .logResponse(Mockito.anyString(), Mockito.anyList(), Mockito.any(), Mockito.anyLong());
}
}
\ No newline at end of file
diff --git a/org.hl7.fhir.report/pom.xml b/org.hl7.fhir.report/pom.xml
index dda6b248f..a497b0985 100644
--- a/org.hl7.fhir.report/pom.xml
+++ b/org.hl7.fhir.report/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
org.hl7.fhir.core
- 6.3.27-SNAPSHOT
+ 6.3.30-SNAPSHOT
../pom.xml
diff --git a/org.hl7.fhir.utilities/pom.xml b/org.hl7.fhir.utilities/pom.xml
index a2e86d2a1..1ec2a2e66 100644
--- a/org.hl7.fhir.utilities/pom.xml
+++ b/org.hl7.fhir.utilities/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
org.hl7.fhir.core
- 6.3.27-SNAPSHOT
+ 6.3.30-SNAPSHOT
../pom.xml
diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/ToolingClientLogger.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/ToolingClientLogger.java
index daa6e739f..fb39acb98 100644
--- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/ToolingClientLogger.java
+++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/ToolingClientLogger.java
@@ -36,7 +36,7 @@ import java.util.List;
public interface ToolingClientLogger {
void logRequest(String method, String url, List headers, byte[] body);
- void logResponse(String outcome, List headers, byte[] body);
+ void logResponse(String outcome, List headers, byte[] body, long length);
String getLastId();
void clearLastId();
diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/http/ManagedWebAccess.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/http/ManagedWebAccess.java
index 6c90c3a44..6dfaf7a35 100644
--- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/http/ManagedWebAccess.java
+++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/http/ManagedWebAccess.java
@@ -64,9 +64,9 @@ public class ManagedWebAccess {
}
public enum WebAccessPolicy {
- DIRECT, // open access to the local file system, though access can be restricted only to files under the paths in AllowedPaths
- MANAGED, // no access except by the FileSystemProxyProvider
- PROHIBITED, // no access at all to File() services
+ DIRECT, // open access to the web, though access can be restricted only to domains in AllowedDomains
+ MANAGED, // no access except by the IWebAccessor
+ PROHIBITED, // no access at all to the web
}
private static WebAccessPolicy accessPolicy = WebAccessPolicy.DIRECT; // for legacy reasons
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 e8af42a88..9925a2acb 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
@@ -18,7 +18,9 @@ public class I18nConstants {
public static final String BAD_FILE_PATH_ERROR = "Bad_file_path_error";
public static final String BASE_PROFILE__HAS_NO_TYPE = "Base_profile__has_no_type";
public static final String BASE__DERIVED_PROFILES_HAVE_DIFFERENT_TYPES____VS___ = "Base__Derived_profiles_have_different_types____vs___";
- public static final String BINDING_ADDITIONAL = "BINDING_ADDITIONAL";
+ public static final String BINDING_ADDITIONAL_D = "BINDING_ADDITIONAL_D";
+ public static final String BINDING_ADDITIONAL_UC = "BINDING_ADDITIONAL_UC";
+ public static final String BINDING_ADDITIONAL_USAGE = "BINDING_ADDITIONAL_USAGE";
public static final String BINDING_MAX = "BINDING_MAX";
public static final String BUNDLE_BUNDLE_ENTRY_CANONICAL = "Bundle_BUNDLE_Entry_Canonical";
public static final String BUNDLE_BUNDLE_ENTRY_DOCUMENT = "Bundle_BUNDLE_Entry_Document";
@@ -1111,4 +1113,7 @@ public class I18nConstants {
public static final String SD_BASE_EXPERIMENTAL = "SD_BASE_EXPERIMENTAL";
public static final String SD_ED_EXPERIMENTAL_BINDING = "SD_ED_EXPERIMENTAL_BINDING";
public static final String VALIDATION_NO_EXPERIMENTAL_CONTENT = "VALIDATION_NO_EXPERIMENTAL_CONTENT";
+ public static final String SD_ED_ADDITIONAL_BINDING_USAGE_UNKNOWN = "SD_ED_ADDITIONAL_BINDING_USAGE_UNKNOWN";
+ public static final String SD_ED_ADDITIONAL_BINDING_USAGE_INVALID_ELEMENT = "SD_ED_ADDITIONAL_BINDING_USAGE_INVALID_ELEMENT";
+ public static final String SD_ED_ADDITIONAL_BINDING_USAGE_INVALID_TYPE = "SD_ED_ADDITIONAL_BINDING_USAGE_INVALID_TYPE";
}
diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/RenderingI18nContext.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/RenderingI18nContext.java
index c3b1be7da..9a2b52a5a 100644
--- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/RenderingI18nContext.java
+++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/RenderingI18nContext.java
@@ -214,6 +214,7 @@ public class RenderingI18nContext extends I18nBase {
public static final String DATA_REND_DATA = "DATA_REND_DATA";
public static final String DATA_REND_DETAILS = "DATA_REND_DETAILS";
public static final String DATA_REND_DETAILS_STATED = "DATA_REND_DETAILS_STATED";
+ public static final String DATA_REND_DETAILS_STATED_ND = "DATA_REND_DETAILS_STATED_ND";
public static final String DATA_REND_DICOM = "DATA_REND_DICOM";
public static final String DATA_REND_DIM = "DATA_REND_DIM";
public static final String DATA_REND_DURATION = "DATA_REND_DURATION";
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 ec0495874..206d90782 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
@@ -8,6 +8,7 @@ import java.text.SimpleDateFormat;
import java.util.*;
import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
import lombok.Getter;
import lombok.Setter;
@@ -77,12 +78,13 @@ public class FilesystemPackageCacheManager extends BasePackageCacheManager imple
private final FilesystemPackageCacheManagerLocks locks;
+ private final FilesystemPackageCacheManagerLocks.LockParameters lockParameters;
+
// When running in testing mode, some packages are provided from the test case repository rather than by the normal means
// the PackageProvider is responsible for this. if no package provider is defined, or it declines to handle the package,
// then the normal means will be used
public interface IPackageProvider {
boolean handlesPackage(String id, String version);
-
InputStreamWithSrc provide(String id, String version) throws IOException;
}
@@ -92,6 +94,7 @@ public class FilesystemPackageCacheManager extends BasePackageCacheManager imple
public static final String PACKAGE_VERSION_REGEX_OPT = "^[A-Za-z][A-Za-z0-9\\_\\-]*(\\.[A-Za-z0-9\\_\\-]+)+(\\#[A-Za-z0-9\\-\\_]+(\\.[A-Za-z0-9\\-\\_]+)*)?$";
private static final Logger ourLog = LoggerFactory.getLogger(FilesystemPackageCacheManager.class);
private static final String CACHE_VERSION = "3"; // second version - see wiki page
+
@Nonnull
private final File cacheFolder;
@@ -100,6 +103,7 @@ public class FilesystemPackageCacheManager extends BasePackageCacheManager imple
private final Map ciList = new HashMap<>();
private JsonArray buildInfo;
private boolean suppressErrors;
+
@Setter
@Getter
private boolean minimalMemory;
@@ -113,9 +117,20 @@ public class FilesystemPackageCacheManager extends BasePackageCacheManager imple
@Getter
private final List packageServers;
+ @With
+ @Getter
+ private final FilesystemPackageCacheManagerLocks.LockParameters lockParameters;
+
public Builder() throws IOException {
this.cacheFolder = getUserCacheFolder();
this.packageServers = getPackageServersFromFHIRSettings();
+ this.lockParameters = null;
+ }
+
+ private Builder(File cacheFolder, List packageServers, FilesystemPackageCacheManagerLocks.LockParameters lockParameters) {
+ this.cacheFolder = cacheFolder;
+ this.packageServers = packageServers;
+ this.lockParameters = lockParameters;
}
private File getUserCacheFolder() throws IOException {
@@ -143,17 +158,12 @@ public class FilesystemPackageCacheManager extends BasePackageCacheManager imple
return PackageServer.getConfiguredServers();
}
- private Builder(File cacheFolder, List packageServers) {
- this.cacheFolder = cacheFolder;
- this.packageServers = packageServers;
- }
-
public Builder withCacheFolder(String cacheFolderPath) throws IOException {
File cacheFolder = ManagedFileAccess.file(cacheFolderPath);
if (!cacheFolder.exists()) {
throw new FHIRException("The folder '" + cacheFolder + "' could not be found");
}
- return new Builder(cacheFolder, this.packageServers);
+ return new Builder(cacheFolder, this.packageServers, this.lockParameters);
}
public Builder withSystemCacheFolder() throws IOException {
@@ -163,32 +173,33 @@ public class FilesystemPackageCacheManager extends BasePackageCacheManager imple
} else {
systemCacheFolder = ManagedFileAccess.file(Utilities.path("/var", "lib", ".fhir", "packages"));
}
- return new Builder(systemCacheFolder, this.packageServers);
+ return new Builder(systemCacheFolder, this.packageServers, this.lockParameters);
}
public Builder withTestingCacheFolder() throws IOException {
- return new Builder(ManagedFileAccess.file(Utilities.path("[tmp]", ".fhir", "packages")), this.packageServers);
+ return new Builder(ManagedFileAccess.file(Utilities.path("[tmp]", ".fhir", "packages")), this.packageServers, this.lockParameters);
}
public FilesystemPackageCacheManager build() throws IOException {
- return new FilesystemPackageCacheManager(cacheFolder, packageServers);
+ final FilesystemPackageCacheManagerLocks locks;
+ try {
+ locks = FilesystemPackageCacheManagerLocks.getFilesystemPackageCacheManagerLocks(cacheFolder);
+ } catch (RuntimeException e) {
+ if (e.getCause() instanceof IOException) {
+ throw (IOException) e.getCause();
+ } else {
+ throw e;
+ }
+ }
+ return new FilesystemPackageCacheManager(cacheFolder, packageServers, locks, lockParameters);
}
}
- private FilesystemPackageCacheManager(@Nonnull File cacheFolder, @Nonnull List packageServers) throws IOException {
+ private FilesystemPackageCacheManager(@Nonnull File cacheFolder, @Nonnull List packageServers, @Nonnull FilesystemPackageCacheManagerLocks locks, @Nullable FilesystemPackageCacheManagerLocks.LockParameters lockParameters) throws IOException {
super(packageServers);
this.cacheFolder = cacheFolder;
-
- try {
- this.locks = FilesystemPackageCacheManagerLocks.getFilesystemPackageCacheManagerLocks(cacheFolder);
- } catch (RuntimeException e) {
- if (e.getCause() instanceof IOException) {
- throw (IOException) e.getCause();
- } else {
- throw e;
- }
- }
-
+ this.locks = locks;
+ this.lockParameters = lockParameters;
prepareCacheFolder();
}
@@ -218,11 +229,35 @@ public class FilesystemPackageCacheManager extends BasePackageCacheManager imple
createIniFile();
}
deleteOldTempDirectories();
+ cleanUpCorruptPackages();
}
return null;
});
}
+ /*
+ Look for .lock files that are not actively held by a process. If found, delete the lock file, and the package
+ referenced.
+ */
+ protected void cleanUpCorruptPackages() throws IOException {
+ for (File file : Objects.requireNonNull(cacheFolder.listFiles())) {
+ if (file.getName().endsWith(".lock")) {
+ if (locks.getCacheLock().canLockFileBeHeldByThisProcess(file)) {
+ String packageDirectoryName = file.getName().substring(0, file.getName().length() - 5);
+ log("Detected potential incomplete package installed in cache: " + packageDirectoryName + ". Attempting to delete");
+
+ File packageDirectory = ManagedFileAccess.file(Utilities.path(cacheFolder, packageDirectoryName));
+ if (packageDirectory.exists()) {
+ Utilities.clearDirectory(packageDirectory.getAbsolutePath());
+ packageDirectory.delete();
+ }
+ file.delete();
+ log("Deleted potential incomplete package: " + packageDirectoryName);
+ }
+ }
+ }
+ }
+
private boolean iniFileExists() throws IOException {
String iniPath = getPackagesIniPath();
File iniFile = ManagedFileAccess.file(iniPath);
@@ -421,7 +456,7 @@ public class FilesystemPackageCacheManager extends BasePackageCacheManager imple
}
return null;
- });
+ }, lockParameters);
}
/**
@@ -465,7 +500,7 @@ public class FilesystemPackageCacheManager extends BasePackageCacheManager imple
return null;
}
return loadPackageInfo(path);
- });
+ }, lockParameters);
if (foundPackage != null) {
if (foundPackage.isIndexed()){
return foundPackage;
@@ -488,7 +523,7 @@ public class FilesystemPackageCacheManager extends BasePackageCacheManager imple
String path = Utilities.path(cacheFolder, foundPackageFolder);
output.checkIndexed(path);
return output;
- });
+ }, lockParameters);
}
}
}
@@ -589,7 +624,7 @@ public class FilesystemPackageCacheManager extends BasePackageCacheManager imple
throw e;
}
return npmPackage;
- });
+ }, lockParameters);
}
private void log(String s) {
diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/FilesystemPackageCacheManagerLocks.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/FilesystemPackageCacheManagerLocks.java
index d674c750e..b32dda96d 100644
--- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/FilesystemPackageCacheManagerLocks.java
+++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/FilesystemPackageCacheManagerLocks.java
@@ -1,14 +1,19 @@
package org.hl7.fhir.utilities.npm;
import lombok.Getter;
-import org.hl7.fhir.utilities.TextFile;
+import lombok.With;
import org.hl7.fhir.utilities.Utilities;
+import org.hl7.fhir.utilities.filesystem.ManagedFileAccess;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
+import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
@@ -27,9 +32,23 @@ public class FilesystemPackageCacheManagerLocks {
private final File cacheFolder;
- private final Long lockTimeoutTime;
+ private static final LockParameters lockParameters = new LockParameters();
- private final TimeUnit lockTimeoutTimeUnit;
+ public static class LockParameters {
+ @Getter @With
+ private final long lockTimeoutTime;
+ @Getter @With
+ private final TimeUnit lockTimeoutTimeUnit;
+
+ public LockParameters() {
+ this(60L, TimeUnit.SECONDS);
+ }
+
+ public LockParameters(long lockTimeoutTime, TimeUnit lockTimeoutTimeUnit) {
+ this.lockTimeoutTime = lockTimeoutTime;
+ this.lockTimeoutTimeUnit = lockTimeoutTimeUnit;
+ }
+ }
/**
* This method is intended to be used only for testing purposes.
@@ -43,21 +62,9 @@ public class FilesystemPackageCacheManagerLocks {
* @throws IOException
*/
public FilesystemPackageCacheManagerLocks(File cacheFolder) throws IOException {
- this(cacheFolder, 60L, TimeUnit.SECONDS);
- }
-
- private FilesystemPackageCacheManagerLocks(File cacheFolder, Long lockTimeoutTime, TimeUnit lockTimeoutTimeUnit) throws IOException {
this.cacheFolder = cacheFolder;
- this.lockTimeoutTime = lockTimeoutTime;
- this.lockTimeoutTimeUnit = lockTimeoutTimeUnit;
}
- /**
- * This method is intended to be used only for testing purposes.
- */
- protected FilesystemPackageCacheManagerLocks withLockTimeout(Long lockTimeoutTime, TimeUnit lockTimeoutTimeUnit) throws IOException {
- return new FilesystemPackageCacheManagerLocks(cacheFolder, lockTimeoutTime, lockTimeoutTimeUnit);
- }
/**
* Returns a single FilesystemPackageCacheManagerLocks instance for the given cacheFolder.
@@ -102,6 +109,19 @@ public class FilesystemPackageCacheManagerLocks {
}
return result;
}
+
+ public boolean canLockFileBeHeldByThisProcess(File lockFile) throws IOException {
+ return doWriteWithLock(() -> {
+ try (FileChannel channel = new RandomAccessFile(lockFile, "rw").getChannel()) {
+ FileLock fileLock = channel.tryLock(0, Long.MAX_VALUE, false);
+ if (fileLock != null) {
+ fileLock.release();
+ channel.close();
+ return true;
+ }
+ }
+ return false;});
+ }
}
public class PackageLock {
@@ -114,15 +134,43 @@ public class FilesystemPackageCacheManagerLocks {
this.lock = lock;
}
- private void checkForLockFileWaitForDeleteIfExists(File lockFile) throws IOException {
+ private void checkForLockFileWaitForDeleteIfExists(File lockFile, @Nonnull LockParameters lockParameters) throws IOException {
if (!lockFile.exists()) {
return;
}
+
+ // Check if the file is locked by a process. If it is not, it is likely an incomplete package cache install, and
+ // we should throw an exception.
+ if (lockFile.isFile()) {
+ try (FileChannel channel = new RandomAccessFile(lockFile, "rw").getChannel()) {
+ FileLock fileLock = channel.tryLock(0, Long.MAX_VALUE, false);
+ if (fileLock != null) {
+ fileLock.release();
+ channel.close();
+ throw new IOException("Lock file exists, but is not locked by a process: " + lockFile.getName());
+ }
+ System.out.println("File is locked.");
+ }
+ }
+ try {
+ waitForLockFileDeletion(lockFile, lockParameters);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw new IOException("Thread interrupted while waiting for lock", e);
+ }
+ }
+
+ /*
+ Wait for the lock file to be deleted. If the lock file is not deleted within the timeout or if the thread is
+ interrupted, an IOException is thrown.
+ */
+ private void waitForLockFileDeletion(File lockFile, @Nonnull LockParameters lockParameters) throws IOException, InterruptedException {
+
try (WatchService watchService = FileSystems.getDefault().newWatchService()) {
Path dir = lockFile.getParentFile().toPath();
dir.register(watchService, StandardWatchEventKinds.ENTRY_DELETE);
- WatchKey key = watchService.poll(lockTimeoutTime, lockTimeoutTimeUnit);
+ WatchKey key = watchService.poll(lockParameters.lockTimeoutTime, lockParameters.lockTimeoutTimeUnit);
if (key == null) {
// It is possible that the lock file is deleted before the watch service is registered, so if we timeout at
// this point, we should check if the lock file still exists.
@@ -141,24 +189,33 @@ public class FilesystemPackageCacheManagerLocks {
key.reset();
}
}
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- throw new IOException("Error reading package.", e);
} catch (TimeoutException e) {
- throw new IOException("Error reading package.", e);
+ throw new IOException("Package cache timed out waiting for lock.", e);
}
}
- public T doReadWithLock(FilesystemPackageCacheManager.CacheLockFunction f) throws IOException {
+ /**
+ * Wraps the execution of a package read function with the appropriate cache, package, and .lock file locking and
+ * checks.
+ *
+ * @param function The function to execute
+ * @param lockParameters The parameters for the lock
+ * @return The return of the function
+ * @param The return type of the function
+ * @throws IOException If an error occurs while managing locking.
+ */
+ public T doReadWithLock(FilesystemPackageCacheManager.CacheLockFunction function, @Nullable LockParameters lockParameters) throws IOException {
+ final LockParameters resolvedLockParameters = lockParameters != null ? lockParameters : FilesystemPackageCacheManagerLocks.lockParameters;
+
cacheLock.getLock().readLock().lock();
lock.readLock().lock();
- checkForLockFileWaitForDeleteIfExists(lockFile);
+ checkForLockFileWaitForDeleteIfExists(lockFile, resolvedLockParameters);
T result = null;
try {
- result = f.get();
+ result = function.get();
} finally {
lock.readLock().unlock();
cacheLock.getLock().readLock().unlock();
@@ -166,35 +223,55 @@ public class FilesystemPackageCacheManagerLocks {
return result;
}
- public T doWriteWithLock(FilesystemPackageCacheManager.CacheLockFunction f) throws IOException {
+ /**
+ * Wraps the execution of a package write function with the appropriate cache, package, and .lock file locking and
+ * checks.
+ *
+ * @param function The function to execute
+ * @param lockParameters The parameters for the lock
+ * @return The return of the function
+ * @param The return type of the function
+ * @throws IOException If an error occurs while managing locking.
+ */
+ public T doWriteWithLock(FilesystemPackageCacheManager.CacheLockFunction function, @Nullable LockParameters lockParameters) throws IOException {
+ final LockParameters resolvedLockParameters = lockParameters != null ? lockParameters : FilesystemPackageCacheManagerLocks.lockParameters;
+
cacheLock.getLock().writeLock().lock();
lock.writeLock().lock();
- if (!lockFile.isFile()) {
- try {
- TextFile.stringToFile("", lockFile);
- } catch (IOException e) {
- e.printStackTrace();
- return null;
- }
- }
+ /*TODO Eventually, this logic should exist in a Lockfile class so that it isn't duplicated between the main code and
+ the test code.
+ */
try (FileChannel channel = new RandomAccessFile(lockFile, "rw").getChannel()) {
- FileLock fileLock = null;
- while (fileLock == null) {
- fileLock = channel.tryLock(0, Long.MAX_VALUE, true);
- if (fileLock == null) {
- Thread.sleep(100); // Wait and retry
- }
+
+ FileLock fileLock = channel.tryLock(0, Long.MAX_VALUE, false);
+
+ if (fileLock == null) {
+ waitForLockFileDeletion(lockFile, resolvedLockParameters);
+ fileLock = channel.tryLock(0, Long.MAX_VALUE, false);
+ }
+ if (fileLock == null) {
+ throw new IOException("Failed to acquire lock on file: " + lockFile.getName());
+ }
+
+ if (!lockFile.isFile()) {
+ final ByteBuffer buff = ByteBuffer.wrap(String.valueOf(ProcessHandle.current().pid()).getBytes(StandardCharsets.UTF_8));
+ channel.write(buff);
}
T result = null;
try {
- result = f.get();
+ result = function.get();
} finally {
+
+ lockFile.renameTo(ManagedFileAccess.file(File.createTempFile(lockFile.getName(), ".lock-renamed").getAbsolutePath()));
+
fileLock.release();
channel.close();
+
if (!lockFile.delete()) {
lockFile.deleteOnExit();
}
+
lock.writeLock().unlock();
cacheLock.getLock().writeLock().unlock();
}
diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageHacker.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageHacker.java
index 225bdd409..05e7e94c4 100644
--- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageHacker.java
+++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageHacker.java
@@ -12,6 +12,7 @@ import java.util.Map;
import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.Utilities;
+import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.utilities.filesystem.ManagedFileAccess;
import org.hl7.fhir.utilities.json.model.JsonArray;
import org.hl7.fhir.utilities.json.model.JsonObject;
@@ -43,7 +44,44 @@ public class PackageHacker {
// new PackageHacker().edit("/Users/grahamegrieve/web/hl7.org/fhir/6.0.0-ballot2/hl7.fhir.r6.search.tgz");
// new PackageHacker().edit("/Users/grahamegrieve/web/hl7.org/fhir/us/core/v311/package.tgz", "http://hl7.org/fhir/us/core/STU3.1.1");
- new PackageHacker().edit("/Users/grahamegrieve/web/hl7.org/fhir/us/core/v700/package.tgz", "http://hl7.org/fhir/us/core/STU7");
+ // new PackageHacker().edit("/Users/grahamegrieve/web/hl7.org/fhir/us/core/v700/package.tgz", "http://hl7.org/fhir/us/core/STU7");
+
+ PackageHacker self = new PackageHacker();
+// self.cloneToR4B("/Users/grahamegrieve/web/terminology.hl7.org/hl7.terminology.r4.tgz", "/Users/grahamegrieve/web/terminology.hl7.org/hl7.terminology.r4b.tgz");
+// self.cloneToR4B("/Users/grahamegrieve/web/terminology.hl7.org/1.0.0/hl7.terminology.r4.tgz", "/Users/grahamegrieve/web/terminology.hl7.org/1.0.0/hl7.terminology.r4b.tgz");
+// self.cloneToR4B("/Users/grahamegrieve/web/terminology.hl7.org/2.0.0/hl7.terminology.r4.tgz", "/Users/grahamegrieve/web/terminology.hl7.org/2.0.0/hl7.terminology.r4b.tgz");
+ self.cloneToR4B("/Users/grahamegrieve/web/terminology.hl7.org/2.1.0/hl7.terminology.r4.tgz", "/Users/grahamegrieve/web/terminology.hl7.org/2.1.0/hl7.terminology.r4b.tgz");
+// self.cloneToR4B("/Users/grahamegrieve/web/terminology.hl7.org/3.0.0/hl7.terminology.r4.tgz", "/Users/grahamegrieve/web/terminology.hl7.org/3.0.0/hl7.terminology.r4b.tgz");
+// self.cloneToR4B("/Users/grahamegrieve/web/terminology.hl7.org/3.1.0/hl7.terminology.r4.tgz", "/Users/grahamegrieve/web/terminology.hl7.org/3.1.0/hl7.terminology.r4b.tgz");
+// self.cloneToR4B("/Users/grahamegrieve/web/terminology.hl7.org/4.0.0/hl7.terminology.r4.tgz", "/Users/grahamegrieve/web/terminology.hl7.org/4.0.0/hl7.terminology.r4b.tgz");
+// self.cloneToR4B("/Users/grahamegrieve/web/terminology.hl7.org/5.0.0/hl7.terminology.r4.tgz", "/Users/grahamegrieve/web/terminology.hl7.org/5.0.0/hl7.terminology.r4b.tgz");
+// self.cloneToR4B("/Users/grahamegrieve/web/terminology.hl7.org/5.1.0/hl7.terminology.r4.tgz", "/Users/grahamegrieve/web/terminology.hl7.org/5.1.0/hl7.terminology.r4b.tgz");
+// self.cloneToR4B("/Users/grahamegrieve/web/terminology.hl7.org/5.2.0/hl7.terminology.r4.tgz", "/Users/grahamegrieve/web/terminology.hl7.org/5.2.0/hl7.terminology.r4b.tgz");
+// self.cloneToR4B("/Users/grahamegrieve/web/terminology.hl7.org/5.3.0/hl7.terminology.r4.tgz", "/Users/grahamegrieve/web/terminology.hl7.org/5.3.0/hl7.terminology.r4b.tgz");
+// self.cloneToR4B("/Users/grahamegrieve/web/terminology.hl7.org/5.4.0/hl7.terminology.r4.tgz", "/Users/grahamegrieve/web/terminology.hl7.org/5.4.0/hl7.terminology.r4b.tgz");
+// self.cloneToR4B("/Users/grahamegrieve/web/terminology.hl7.org/5.5.0/hl7.terminology.r4.tgz", "/Users/grahamegrieve/web/terminology.hl7.org/5.5.0/hl7.terminology.r4b.tgz");
+// self.cloneToR4B("/Users/grahamegrieve/web/terminology.hl7.org/6.0.0/hl7.terminology.r4.tgz", "/Users/grahamegrieve/web/terminology.hl7.org/6.0.0/hl7.terminology.r4b.tgz");
+// self.cloneToR4B("/Users/grahamegrieve/web/terminology.hl7.org/6.0.1/hl7.terminology.r4.tgz", "/Users/grahamegrieve/web/terminology.hl7.org/6.0.1/hl7.terminology.r4b.tgz");
+// self.cloneToR4B("/Users/grahamegrieve/web/terminology.hl7.org/6.0.2/hl7.terminology.r4.tgz", "/Users/grahamegrieve/web/terminology.hl7.org/6.0.2/hl7.terminology.r4b.tgz");
+ }
+
+ private void cloneToR4B(String src, String dst) throws IOException {
+ FileInputStream fs = ManagedFileAccess.inStream(src);
+ NpmPackage pck = NpmPackage.fromPackage(fs);
+ System.out.println(nice(pck.getNpm()));
+ JsonObject json = pck.getNpm();
+ String name = json.asString("name");
+ json.remove("name");
+ json.add("name", name.replace(".r4", ".r4b"));
+ json.remove("fhirVersions");
+ json.remove("dependencies");
+ JsonArray fv = new JsonArray();
+ json.add("fhirVersions", fv);
+ fv.add("4.3.0");
+ JsonObject dep = new JsonObject();
+ json.add("dependencies", dep);
+ dep.add(VersionUtilities.packageForVersion("4.3.0"), "4.3.0");
+ pck.save(new FileOutputStream(dst));
}
// private void massEdit(File dir) throws IOException {
diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/tests/CacheVerificationLogger.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/tests/CacheVerificationLogger.java
index 1be1eab5b..2ff232a1e 100644
--- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/tests/CacheVerificationLogger.java
+++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/tests/CacheVerificationLogger.java
@@ -33,7 +33,7 @@ public class CacheVerificationLogger implements ToolingClientLogger {
}
@Override
- public void logResponse(String outcome, List headers, byte[] body) {
+ public void logResponse(String outcome, List headers, byte[] body, long start) {
}
diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xml/IXMLWriter.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xml/IXMLWriter.java
index 80459e7ad..826ac97c0 100644
--- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xml/IXMLWriter.java
+++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xml/IXMLWriter.java
@@ -1,5 +1,5 @@
-package org.hl7.fhir.utilities.xml;
-
+package org.hl7.fhir.utilities.xml;
+
/*
Copyright (c) 2011+, HL7, Inc.
All rights reserved.
@@ -28,80 +28,85 @@ package org.hl7.fhir.utilities.xml;
POSSIBILITY OF SUCH DAMAGE.
*/
-
-
-
-import java.io.IOException;
-
-import org.hl7.fhir.utilities.ElementDecoration;
-
-
-/**
- * Generalize
- * @author dennisn
- */
-public interface IXMLWriter {
-
- public abstract void start() throws IOException;
- public abstract void end() throws IOException;
-
- public abstract void attribute(String namespace, String name, String value, boolean onlyIfNotEmpty) throws IOException;
- public abstract void attribute(String namespace, String name, String value) throws IOException;
- public abstract void attribute(String name, String value, boolean onlyIfNotEmpty) throws IOException;
- public abstract void attribute(String name, String value) throws IOException;
- public abstract void attributeNoLines(String name, String value) throws IOException;
-
- public abstract boolean namespaceDefined(String namespace);
- public abstract boolean abbreviationDefined(String abbreviation);
- public abstract String getDefaultNamespace();
- public abstract void namespace(String namespace) throws IOException;
- public abstract void setDefaultNamespace(String namespace) throws IOException;
- public abstract void namespace(String namespace, String abbreviation) throws IOException;
-
- public abstract void comment(String comment, boolean doPretty) throws IOException;
- public abstract void decorate(ElementDecoration decoration) throws IOException;
- public abstract void setSchemaLocation(String ns, String loc) throws IOException;
-
- public abstract void enter(String name) throws IOException;
- public abstract void enter(String namespace, String name) throws IOException;
- public abstract void enter(String namespace, String name, String comment) throws IOException;
-
- public abstract void exit() throws IOException;
- public abstract void exit(String name) throws IOException;
- public abstract void exit(String namespace, String name) throws IOException;
- public abstract void exitToLevel(int count) throws IOException;
-
-
- public abstract void element(String namespace, String name, String content, boolean onlyIfNotEmpty) throws IOException;
- public abstract void element(String namespace, String name, String content, String comment) throws IOException;
- public abstract void element(String namespace, String name, String content) throws IOException;
- public abstract void element(String name, String content, boolean onlyIfNotEmpty) throws IOException;
- public abstract void element(String name, String content) throws IOException;
- public abstract void element(String name) throws IOException;
-
- public abstract void text(String content) throws IOException;
- public abstract void text(String content, boolean dontEscape) throws IOException;
-
- public abstract void cData(String text) throws IOException;
-
- public abstract void writeBytes(byte[] bytes) throws IOException;
-
- public abstract boolean isPretty() throws IOException;
- public abstract void setPretty(boolean pretty) throws IOException;
-
- /**
- * Start comment inserts a
- * so the comment doesn't close prematurely.
- * @throws IOException
- */
- public abstract void startCommentBlock() throws IOException;
- public abstract void endCommentBlock() throws IOException;
- public abstract void escapedText(String content) throws IOException;
-
- // this is only implemented by an implementation that is producing an xhtml representation, and is able to render elements as hyperlinks
- public abstract void link(String href);
- public abstract void anchor(String name);
- public abstract void externalLink(String ref) throws IOException;
+
+
+
+import java.io.IOException;
+
+import org.hl7.fhir.utilities.ElementDecoration;
+
+
+/**
+ * Generalize
+ * @author dennisn
+ */
+public interface IXMLWriter {
+
+ public abstract void start() throws IOException;
+ public abstract void end() throws IOException;
+
+ public abstract void attribute(String namespace, String name, String value, boolean onlyIfNotEmpty) throws IOException;
+ public abstract void attribute(String namespace, String name, String value) throws IOException;
+ public abstract void attribute(String name, String value, boolean onlyIfNotEmpty) throws IOException;
+ public abstract void attribute(String name, String value) throws IOException;
+ public abstract void attributeNoLines(String name, String value) throws IOException;
+
+ public abstract boolean namespaceDefined(String namespace);
+ public abstract boolean abbreviationDefined(String abbreviation);
+ public abstract String getDefaultNamespace();
+ public abstract void namespace(String namespace) throws IOException;
+ public abstract void setDefaultNamespace(String namespace) throws IOException;
+ public abstract void namespace(String namespace, String abbreviation) throws IOException;
+
+ public abstract void comment(String comment, boolean doPretty) throws IOException;
+ public abstract void decorate(ElementDecoration decoration) throws IOException;
+ public abstract void setSchemaLocation(String ns, String loc) throws IOException;
+
+ public abstract void enter(String name) throws IOException;
+ public abstract void enter(String namespace, String name) throws IOException;
+ public abstract void enter(String namespace, String name, String comment) throws IOException;
+
+ public abstract void exit() throws IOException;
+ public abstract void exit(String name) throws IOException;
+ public abstract void exit(String namespace, String name) throws IOException;
+ public abstract void exitToLevel(int count) throws IOException;
+
+
+ public abstract void element(String namespace, String name, String content, boolean onlyIfNotEmpty) throws IOException;
+ public abstract void element(String namespace, String name, String content, String comment) throws IOException;
+ public abstract void element(String namespace, String name, String content) throws IOException;
+ public abstract void element(String name, String content, boolean onlyIfNotEmpty) throws IOException;
+ public abstract void element(String name, String content) throws IOException;
+ public abstract void element(String name) throws IOException;
+
+ public abstract void text(String content) throws IOException;
+ public abstract void text(String content, boolean dontEscape) throws IOException;
+
+ public abstract void cData(String text) throws IOException;
+
+ public abstract void writeBytes(byte[] bytes) throws IOException;
+
+ public abstract boolean isPretty() throws IOException;
+ public abstract void setPretty(boolean pretty) throws IOException;
+
+ /**
+ * Start comment inserts a
+ * so the comment doesn't close prematurely.
+ * @throws IOException
+ */
+ public abstract void startCommentBlock() throws IOException;
+ public abstract void endCommentBlock() throws IOException;
+ public abstract void escapedText(String content) throws IOException;
+
+ // this is only implemented by an implementation that is producing an xhtml representation, and is able to render elements as hyperlinks
+ public abstract void link(String href);
+ public abstract void anchor(String name);
+ public abstract void externalLink(String ref) throws IOException;
+
+ // this is only implemented by an implementation that is producing an xhtml representation and handles ellipsing elements
+ public abstract boolean canElide();
+ public abstract void elide() throws IOException;
+ public abstract void attributeElide();
}
\ No newline at end of file
diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xml/XMLWriter.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xml/XMLWriter.java
index a8e40fee0..cedf9ed71 100644
--- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xml/XMLWriter.java
+++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xml/XMLWriter.java
@@ -1,5 +1,5 @@
-package org.hl7.fhir.utilities.xml;
-
+package org.hl7.fhir.utilities.xml;
+
/*
Copyright (c) 2011+, HL7, Inc.
All rights reserved.
@@ -28,889 +28,901 @@ package org.hl7.fhir.utilities.xml;
POSSIBILITY OF SUCH DAMAGE.
*/
-
-
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.UnsupportedEncodingException;
-
-import org.hl7.fhir.utilities.ElementDecoration;
-
-/**
- * XML Writer class.
- */
-public class XMLWriter extends OutputStreamWriter implements IXMLWriter {
-
- private boolean xmlHeader = true;
- private String charset;
- private boolean prettyBase;
- private boolean prettyHeader;
- private boolean pendingClose;
- private boolean pendingOpen;
- private String pendingComment;
- private int lineType = LINE_UNIX;
- private OutputStream stream;
- private boolean started = false;
- private String[] specialAttributeNames = new String[] {"id", "name" };
- private boolean sortAttributes;
- private int attributeLineWrap;
- private boolean xml1_1;
-
- public final static int LINE_UNIX = 0;
- public final static int LINE_WINDOWS = 1;
-
- public XMLWriter(OutputStream stream, String charset, boolean xml1_1) throws UnsupportedEncodingException {
- super(stream, charset);
- this.stream = stream;
- this.charset = charset;
- this.xml1_1 = xml1_1;
- }
- public XMLWriter(OutputStream stream, String charset) throws UnsupportedEncodingException {
- super(stream, charset);
- this.stream = stream;
- this.charset = charset;
- this.xml1_1 = false;
- }
-
- protected boolean condition(boolean bTest, String message) throws IOException {
- if (!bTest)
- throw new IOException(message);
- return bTest;
- }
-
- // -- writing context ------------------------------------------------
-
-
-
- /**
- * Returns the encoding.
- *
- * @param charset
- * @return encoding
- * @throws IOException
- */
- public static String getXMLCharsetName(String charset) throws IOException {
- if (charset == null || charset.equals(""))
- return "UTF-8";
- else if (charset.equals("US-ASCII"))
- return "UTF-8";
- else if (XMLUtil.charSetImpliesAscii(charset))
- return "ISO-8859-1";
- else if (charset.equals("UTF-8"))
- return "UTF-8";
- else if (charset.equals("UTF-16") || charset.equals("UTF-16BE") || charset.equals("UTF-16LE"))
- return "UTF-16";
- else
- throw new IOException("Unknown charset encoding "+charset);
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.ohf.utilities.xml.IXMLWriter#start()
- */
- @Override
- public void start() throws IOException {
- condition(!started, "attempt to start after starting");
- levels.clear();
- attributes = null;
- try {
- if (xmlHeader) {
- write("");
- if (prettyBase || prettyHeader)
- write(lineType == LINE_UNIX ? "\n" : "\r\n");
- }
- } catch (UnsupportedEncodingException e) {
- // TODO Auto-generated catch block
- throw new IOException(e.getMessage());
- }
- started = true;
- }
-
- private void checkStarted () throws IOException {
- condition(started, "not started");
- }
-
- private void checkInElement() throws IOException {
- condition(levels.size() > 0, "not in an element");
- }
-
- // -- attributes ----------------------------------------------------
-
- private String[][] attributes;
-
- private void addAttribute(String name, String value) throws IOException {
- addAttribute(name, value, false);
- }
-
- private void addAttribute(String name, String value, boolean noLines) throws IOException {
- if (!XMLUtil.isNMToken(name))
- throw new IOException("XML name "+name+" is not valid for value '"+value+"'");
-
- newLevelIfRequired();
- value = XMLUtil.escapeXML(value, charset, noLines);
-
- if (attributes == null)
- attributes = new String[][] {{name, value}};
- else {
- String[][] newattr = new String[attributes.length+1][];
- for (int i = 0; i < attributes.length; i++) {
- condition(!attributes[i][0].equals(name), "attempt to define attribute with name "+name+" more than once for value '"+value+"'");
- newattr[i] = attributes[i];
- }
- attributes = newattr;
- attributes[attributes.length-1] = new String[] {name, value};
- }
- }
-
- protected String getAttribute(String name) {
- if (attributes != null) {
- for (int i = 0; i < attributes.length; i++) {
- if (attributes[i][0].equals(name)) {
- return attributes[i][1];
- }
- }
- }
- return null;
- }
-
- protected void setAttribute(String name, String value) throws IOException {
- newLevelIfRequired();
- if (attributes == null)
- addAttribute(name, value, false);
- else {
- for (int i = 0; i < attributes.length; i++) {
- if (attributes[i][0].equals(name)) {
- attributes[i][1] = XMLUtil.escapeXML(value, charset, false);
- return;
- }
- }
- addAttribute(name, value);
- }
- }
-
- protected void commitAttributes() throws IOException {
-
- }
-
-
- private boolean nameIsSpecial(String name) {
- for (int i = 0; i < specialAttributeNames.length; i++) {
- String n = specialAttributeNames[i];
- if (n.equalsIgnoreCase(name))
- return true;
- }
- return false;
- }
-
- private void writeAttributes(int col) throws IOException {
- commitAttributes();
- if (attributes != null && sortAttributes)
- sortAttributes();
- int c = col;
- c = writeAttributeSet(true, c, col);
- writeAttributeSet(false, c, col);
- attributes = null;
- }
-
-
- private void sortAttributes() {
- // bubble sort - look, it's easy
- for (int i = 0; i < attributes.length - 1; i++) {
- for (int j = 0; j < attributes.length - 1; j++) {
- if (String.CASE_INSENSITIVE_ORDER.compare(attributes[j][0], attributes[j+1][0]) < 0) {
- String[] t = attributes[j];
- attributes[j] = attributes[j+1];
- attributes[j+1] = t;
- }
- }
- }
-
- }
-
-
- private int writeAttributeSet(boolean special, int col, int wrap) throws IOException {
- // first pass: name, id
- if (attributes != null) {
- for (int i=0; i < attributes.length; i++) {
- String[] element = attributes[i];
- if (nameIsSpecial(element[0]) == special) {
- col = col + element[0].length()+element[1].length() + 4;
- if (isPretty() && attributeLineWrap > 0 && col > attributeLineWrap && col > wrap) {
- write(lineType == LINE_UNIX ? "\n" : "\r\n");
- for (int j = 0; j < wrap; j++)
- write(" ");
- col = wrap;
- }
- write(' ');
- write(element[0]);
- write("=\"");
- if (element[1] != null)
- write(xmlEscape(element[1]));
- write("\"");
- }
- }
- }
- return col;
- }
-
- protected String xmlEscape(String s) {
- StringBuilder b = new StringBuilder();
- for (char c : s.toCharArray()) {
- if (c < ' ') {
- b.append("");
- b.append(Integer.toHexString(c).toUpperCase());
- b.append(";");
- } else
- b.append(c);
- }
- return b.toString();
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.ohf.utilities.xml.IXMLWriter#attribute(java.lang.String, java.lang.String, java.lang.String, boolean)
- */
- @Override
- public void attribute(String namespace, String name, String value, boolean onlyIfNotEmpty) throws IOException {
- if (!onlyIfNotEmpty || value != null && !value.equals(""))
- attribute(namespace, name, value);
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.ohf.utilities.xml.IXMLWriter#attribute(java.lang.String, java.lang.String, java.lang.String)
- */
- @Override
- public void attribute(String namespace, String name, String value) throws IOException {
-
- checkStarted();
- if (namespace == null || namespace.equals(""))
- addAttribute(name, value);
- else
- addAttribute(getNSAbbreviation(namespace)+name, value);
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.ohf.utilities.xml.IXMLWriter#attribute(java.lang.String, java.lang.String, boolean)
- */
- @Override
- public void attribute(String name, String value, boolean onlyIfNotEmpty) throws IOException {
- if (!onlyIfNotEmpty || value != null && !value.equals(""))
- attribute(name, value);
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.ohf.utilities.xml.IXMLWriter#attribute(java.lang.String, java.lang.String)
- */
- @Override
- public void attribute(String name, String value) throws IOException {
- checkStarted();
- addAttribute(name, value);
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.ohf.utilities.xml.IXMLWriter#attributeNoLines(java.lang.String, java.lang.String)
- */
- @Override
- public void attributeNoLines(String name, String value) throws IOException {
- checkStarted();
- addAttribute(name, value, true);
- }
-
- // -- levels -------------------------------------------------
-
- private XMLWriterStateStack levels = new XMLWriterStateStack();
-
- private void newLevelIfRequired() throws IOException {
- if (!pendingOpen) {
- if (!levels.empty())
- levels.current().seeChild();
- XMLWriterState level = new XMLWriterState();
- level.setPretty(isPretty());
- levels.push(level);
- pendingOpen = true;
- }
- }
-
- // -- namespaces ---------------------------------------------
-
-
- private void defineNamespace(String namespace, String abbrev) throws IOException {
- checkStarted();
- if (namespace != null && !namespace.equals("")) {
- if ("".equals(abbrev))
- abbrev = null;
-
- newLevelIfRequired();
-
- levels.current().addNamespaceDefn(namespace, abbrev);
- if (abbrev == null)
- addAttribute("xmlns", namespace);
- else
- addAttribute("xmlns:"+abbrev, namespace);
- }
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.ohf.utilities.xml.IXMLWriter#findByNamespace(java.lang.String)
- */
- public XMLNamespace findByNamespace(String namespace) {
- for (int i = levels.size() - 1; i >= 0; i--) {
- XMLNamespace ns = levels.item(i).getDefnByNamespace(namespace);
- if (ns != null)
- return ns;
- }
- return null;
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.ohf.utilities.xml.IXMLWriter#namespaceDefined(java.lang.String)
- */
- @Override
- public boolean namespaceDefined(String namespace) {
- return namespace == null || namespace.equals("") || findByNamespace(namespace) != null;
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.ohf.utilities.xml.IXMLWriter#findByAbbreviation(java.lang.String)
- */
- public XMLNamespace findByAbbreviation(String abbreviation) {
- for (int i = levels.size() - 1; i >= 0; i--) {
- XMLNamespace ns = levels.item(i).getDefnByAbbreviation(abbreviation);
- if (ns != null)
- return ns;
- }
- return null;
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.ohf.utilities.xml.IXMLWriter#abbreviationDefined(java.lang.String)
- */
- @Override
- public boolean abbreviationDefined(String abbreviation) {
- return findByAbbreviation(abbreviation) != null;
- }
-
- protected XMLNamespace findDefaultNamespace() {
- for (int i = levels.size() - 1; i >= 0; i--) {
- XMLNamespace ns = levels.item(i).getDefaultNamespace();
- if (ns != null)
- return ns;
- }
- return null;
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.ohf.utilities.xml.IXMLWriter#getDefaultNamespace()
- */
- @Override
- public String getDefaultNamespace() {
- XMLNamespace ns = findDefaultNamespace();
- if (ns == null)
- return null;
- else
- return ns.getNamespace();
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.ohf.utilities.xml.IXMLWriter#namespace(java.lang.String)
- */
- @Override
- public void namespace(String namespace) throws IOException {
- if (!namespaceDefined(namespace)) {
- int index = 0;
- while (abbreviationDefined("ns"+Integer.toString(index)))
- index++;
- defineNamespace(namespace, "ns"+Integer.toString(index));
- }
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.ohf.utilities.xml.IXMLWriter#defaultNamespace(java.lang.String)
- *
- * Replace defaultNamespace()
- */
- @Override
- public void setDefaultNamespace(String namespace) throws IOException {
- if ((namespace == null && getDefaultNamespace() != null) ||
- (namespace != null && !namespace.equals(getDefaultNamespace())))
- defineNamespace(namespace, "");
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.ohf.utilities.xml.IXMLWriter#namespace(java.lang.String, java.lang.String)
- */
- @Override
- public void namespace(String namespace, String abbreviation) throws IOException {
- XMLNamespace ns = findByAbbreviation(abbreviation);
- if (ns == null || !ns.getNamespace().equals(namespace))
- defineNamespace(namespace, abbreviation);
- }
-
-
- private String getNSAbbreviation(String namespace) throws IOException {
- if ("http://www.w3.org/XML/1998/namespace".equals(namespace))
- return "xml:";
-
- if (namespace == null || "".equals(namespace) || "noNamespace".equals(namespace))
- return "";
-
- XMLNamespace ns = findByNamespace(namespace);
- if (ns == null)
- throw new IOException("Namespace "+namespace+" is not defined");
- else if (ns.getAbbreviation() == null)
- return "";
- else
- return ns.getAbbreviation()+":";
- }
-
- // -- public API -----------------------------------------------------------
-
- /* (non-Javadoc)
- * @see org.eclipse.ohf.utilities.xml.IXMLWriter#comment(java.lang.String, boolean)
- */
- @Override
- public void comment(String comment, boolean doPretty) throws IOException {
- checkStarted();
- if (pendingClose) {
- write('>');
- writePendingComment();
- pendingClose = false;
- }
- if (doPretty) {
- writePretty();
- }
- if (levels.inComment())
- write(" ");
- if (doPretty && !isPretty())
- writePretty();
- }
-
-
- private void writePendingComment() throws IOException {
- if (pendingComment != null) {
- if (isPretty())
- write(" ");
- if (levels.inComment())
- write("");
- }
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.ohf.utilities.xml.IXMLWriter#open(java.lang.String, java.lang.String)
- */
- @Override
- public void enter(String namespace, String name) throws IOException {
- enter(namespace, name, null);
- }
-
-
- /* (non-Javadoc)
- * @see org.eclipse.ohf.utilities.xml.IXMLWriter#open(java.lang.String, java.lang.String, java.lang.String)
- */
- @Override
- public void enter(String namespace, String name, String comment) throws IOException {
- if (name == null)
- throw new Error("name == null");
- if (!XMLUtil.isNMToken(name))
- throw new IOException("XML name "+name+" is not valid");
- checkStarted();
- if (pendingClose) {
- write('>');
- writePendingComment();
- pendingClose = false;
- }
-
- if (name == null) {
- throw new IOException("name is null");
- }
- newLevelIfRequired();
- levels.current().setName(name);
- levels.current().setNamespace(namespace);
- int col = writePretty();
- write('<');
- if (namespace == null) {
- write(name);
- col = col + name.length()+1;
- } else {
- String n = getNSAbbreviation(namespace)+name;
- write(n);
- col = col + n.length()+1;
- }
- writeAttributes(col);
- pendingOpen = false;
- pendingClose = true;
- pendingComment = comment;
- }
-
-
- /* (non-Javadoc)
- * @see org.eclipse.ohf.utilities.xml.IXMLWriter#close(java.lang.String)
- */
- @Override
- public void exit(String name) throws IOException {
- checkStarted();
- if (levels.empty())
- throw new IOException("Unable to close null|"+name+", nothing to close");
- if (levels.current().getNamespace() != null || !levels.current().getName().equals(name))
- throw new IOException("Unable to close null|"+name+", found "+levels.current().getNamespace()+"|"+levels.current().getName());
- exit();
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.ohf.utilities.xml.IXMLWriter#close(java.lang.String, java.lang.String)
- */
- @Override
- public void exit(String namespace, String name) throws IOException {
- checkStarted();
- if (levels.empty())
- throw new IOException("Unable to close "+namespace+"|"+name+", nothing to close");
- if (levels == null)
- throw new Error("levels = null");
- if (levels.current() == null)
- throw new Error("levels.current() = null");
- if (levels.current().getName() == null)
- throw new Error("levels.current().getName() = null");
- if (levels.current().getNamespace() == null)
- throw new Error("levels.current().getNamespace() = null");
- if (name == null)
- throw new Error("name = null");
- if (namespace == null)
- throw new Error("namespace = null");
- if (!levels.current().getNamespace().equals(namespace) || !levels.current().getName().equals(name))
- throw new IOException("Unable to close "+namespace+"|"+name+", found "+levels.current().getNamespace()+"|"+levels.current().getName());
- exit();
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.ohf.utilities.xml.IXMLWriter#closeToLevel(int)
- */
- @Override
- public void exitToLevel(int count) throws IOException {
- checkStarted();
- while (levels.size() > count)
- exit();
- }
-
-
- /* (non-Javadoc)
- * @see org.eclipse.ohf.utilities.xml.IXMLWriter#close()
- */
- @Override
- public void close() throws IOException {
- checkStarted();
- if (!levels.empty())
- throw new IOException("Called close before exiting all opened elements");
- super.close();
- }
-
- @Override
- public void end() throws IOException {
- checkStarted();
- if (!levels.empty())
- throw new IOException("Called end() before exiting all opened elements");
- flush();
- }
- @Override
- public void exit() throws IOException {
- checkStarted();
- if (levels.empty()) {
- throw new IOException("Called exit one too many times");
- } else {
- if (pendingClose) {
- write("/>");
- writePendingComment();
- pendingClose = false;
- } else {
- if (levels.current().hasChildren())
- writePretty();
- write("");
- if (levels.current().getNamespace() == null)
- write(levels.current().getName());
- else
- write(getNSAbbreviation(levels.current().getNamespace())+levels.current().getName());
- write('>');
- }
- levels.pop();
- }
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.ohf.utilities.xml.IXMLWriter#open(java.lang.String)
- */
- @Override
- public void enter(String name) throws IOException {
- enter(null, name);
- }
-
-
- /* (non-Javadoc)
- * @see org.eclipse.ohf.utilities.xml.IXMLWriter#element(java.lang.String, java.lang.String, java.lang.String, boolean)
- */
- @Override
- public void element(String namespace, String name, String content, boolean onlyIfNotEmpty) throws IOException {
- if (!onlyIfNotEmpty || content != null && !content.equals(""))
- element(namespace, name, content);
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.ohf.utilities.xml.IXMLWriter#element(java.lang.String, java.lang.String, java.lang.String, java.lang.String)
- */
- @Override
- public void element(String namespace, String name, String content, String comment) throws IOException {
- if (!XMLUtil.isNMToken(name))
- throw new IOException("XML name "+name+" is not valid");
- enter(namespace, name, comment);
- text(content);
- exit();
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.ohf.utilities.xml.IXMLWriter#element(java.lang.String, java.lang.String, java.lang.String)
- */
- @Override
- public void element(String namespace, String name, String content) throws IOException {
- if (!XMLUtil.isNMToken(name))
- throw new IOException("XML name "+name+" is not valid");
- enter(namespace, name);
- text(content);
- exit();
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.ohf.utilities.xml.IXMLWriter#element(java.lang.String, java.lang.String, boolean)
- */
- @Override
- public void element(String name, String content, boolean onlyIfNotEmpty) throws IOException {
- if (!onlyIfNotEmpty || content != null && !content.equals(""))
- element(null, name, content);
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.ohf.utilities.xml.IXMLWriter#element(java.lang.String, java.lang.String)
- */
- @Override
- public void element(String name, String content) throws IOException {
- element(null, name, content);
- }
-
- @Override
- public void element(String name) throws IOException {
- element(null, name, null);
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.ohf.utilities.xml.IXMLWriter#text(java.lang.String)
- */
- @Override
- public void text(String content) throws IOException {
- text(content, false);
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.ohf.utilities.xml.IXMLWriter#text(java.lang.String, boolean)
- *
- * Replace escapeText()
- */
- @Override
- public void text(String content, boolean dontEscape) throws IOException {
- checkInElement();
- if (content != null) {
- if (pendingClose) {
- write(">");
- writePendingComment();
- pendingClose = false;
- }
- if (dontEscape)
- write(content);
- else
- write(XMLUtil.escapeXML(content, charset, false));
- }
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.ohf.utilities.xml.IXMLWriter#cData(java.lang.String)
- */
- @Override
- public void cData(String text) throws IOException {
- text("");
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.ohf.utilities.xml.IXMLWriter#writeBytes(byte[])
- */
- @Override
- public void writeBytes(byte[] bytes) throws IOException {
- checkInElement();
- if (pendingClose) {
- write(">");
- writePendingComment();
- pendingClose = false;
- }
- flush();
- stream.write(bytes);
- }
-
-
- /* (non-Javadoc)
- * @see org.eclipse.ohf.utilities.xml.IXMLWriter#isPretty()
- */
- @Override
- public boolean isPretty() throws IOException {
- return (levels == null || levels.empty()) ? prettyBase : levels.current().isPretty();
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.ohf.utilities.xml.IXMLWriter#setPretty(boolean)
- */
- @Override
- public void setPretty(boolean pretty) throws IOException {
- if (levels == null || levels.empty())
- this.prettyBase = pretty;
- else
- levels.current().setPretty(pretty);
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.ohf.utilities.xml.IXMLWriter#startCommentBlock()
- */
- @Override
- public void startCommentBlock() throws IOException {
- if (levels.inComment())
- throw new IOException("cannot nest comments");
- levels.current().setInComment(true);
- if (isPretty())
- writePretty();
- write("");
- if (isPretty())
- writePretty();
- levels.current().setInComment(false);
- }
-
- public boolean isSortAttributes() {
- return sortAttributes;
- }
-
- public void setSortAttributes(boolean sortAttributes) {
- this.sortAttributes = sortAttributes;
- }
-
-
- public boolean isPrettyHeader() {
- return prettyHeader;
- }
-
- public void setPrettyHeader(boolean pretty) {
- this.prettyHeader = pretty;
- }
-
- public int writePretty() throws IOException {
- return writePretty(true);
- }
-
- public int writePretty(boolean eoln) throws IOException {
- if (isPretty()) {
- if (eoln)
- write(lineType == LINE_UNIX ? "\n" : "\r\n");
- for (int i = 0; i < levels.size() - 1; i++)
- write(" ");
- return (levels.size() - 1) * 2;
- } else
- return 0;
- }
-
- public int getLineType() {
- return lineType;
- }
-
- public void setLineType(int lineType) {
- this.lineType = lineType;
- }
-
- public boolean isXmlHeader() {
- return xmlHeader;
- }
-
- public void setXmlHeader(boolean xmlHeader) {
- this.xmlHeader = xmlHeader;
- }
-
- public String[] getSpecialAttributeNames() {
- return specialAttributeNames;
- }
-
- public void setSpecialAttributeNames(String[] specialAttributeNames) {
- this.specialAttributeNames = specialAttributeNames;
- }
-
- public int getAttributeLineWrap() {
- return attributeLineWrap;
- }
-
- public void setAttributeLineWrap(int attributeLineWrap) {
- this.attributeLineWrap = attributeLineWrap;
- }
-
- @Override
- public void escapedText(String content) throws IOException {
- text("");
- int i = content.length();
- if (isPretty())
- while (i > 0 && (content.charAt(i-1) == '\r' || content.charAt(i-1) == '\n'))
- i--;
- write(content.substring(0, i));
- }
-
- public void processingInstruction(String value) throws IOException {
- write(""+value+"?>");
- if (isPrettyHeader())
- write("\r\n");
- }
-
- @Override
- public void link(String href) {
- // ignore this
-
- }
-
- @Override
- public void anchor(String name) {
- // ignore this
- }
-
- @Override
- public void decorate(ElementDecoration element) throws IOException {
- // nothing...
- }
- @Override
- public void setSchemaLocation(String ns, String loc) throws IOException {
- namespace("http://www.w3.org/2001/XMLSchema-instance", "xsi");
- attribute("http://www.w3.org/2001/XMLSchema-instance", "schemaLocation", ns+" "+loc);
-
- }
- @Override
- public void externalLink(String ref) {
- // ignore this
- }
-
-
+
+
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.UnsupportedEncodingException;
+
+import org.hl7.fhir.utilities.ElementDecoration;
+
+/**
+ * XML Writer class.
+ */
+public class XMLWriter extends OutputStreamWriter implements IXMLWriter {
+
+ private boolean xmlHeader = true;
+ private String charset;
+ private boolean prettyBase;
+ private boolean prettyHeader;
+ private boolean pendingClose;
+ private boolean pendingOpen;
+ private String pendingComment;
+ private int lineType = LINE_UNIX;
+ private OutputStream stream;
+ private boolean started = false;
+ private String[] specialAttributeNames = new String[] {"id", "name" };
+ private boolean sortAttributes;
+ private int attributeLineWrap;
+ private boolean xml1_1;
+
+ public final static int LINE_UNIX = 0;
+ public final static int LINE_WINDOWS = 1;
+
+ public XMLWriter(OutputStream stream, String charset, boolean xml1_1) throws UnsupportedEncodingException {
+ super(stream, charset);
+ this.stream = stream;
+ this.charset = charset;
+ this.xml1_1 = xml1_1;
+ }
+ public XMLWriter(OutputStream stream, String charset) throws UnsupportedEncodingException {
+ super(stream, charset);
+ this.stream = stream;
+ this.charset = charset;
+ this.xml1_1 = false;
+ }
+
+ protected boolean condition(boolean bTest, String message) throws IOException {
+ if (!bTest)
+ throw new IOException(message);
+ return bTest;
+ }
+
+ // -- writing context ------------------------------------------------
+
+
+
+ /**
+ * Returns the encoding.
+ *
+ * @param charset
+ * @return encoding
+ * @throws IOException
+ */
+ public static String getXMLCharsetName(String charset) throws IOException {
+ if (charset == null || charset.equals(""))
+ return "UTF-8";
+ else if (charset.equals("US-ASCII"))
+ return "UTF-8";
+ else if (XMLUtil.charSetImpliesAscii(charset))
+ return "ISO-8859-1";
+ else if (charset.equals("UTF-8"))
+ return "UTF-8";
+ else if (charset.equals("UTF-16") || charset.equals("UTF-16BE") || charset.equals("UTF-16LE"))
+ return "UTF-16";
+ else
+ throw new IOException("Unknown charset encoding "+charset);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ohf.utilities.xml.IXMLWriter#start()
+ */
+ @Override
+ public void start() throws IOException {
+ condition(!started, "attempt to start after starting");
+ levels.clear();
+ attributes = null;
+ try {
+ if (xmlHeader) {
+ write("");
+ if (prettyBase || prettyHeader)
+ write(lineType == LINE_UNIX ? "\n" : "\r\n");
+ }
+ } catch (UnsupportedEncodingException e) {
+ // TODO Auto-generated catch block
+ throw new IOException(e.getMessage());
+ }
+ started = true;
+ }
+
+ private void checkStarted () throws IOException {
+ condition(started, "not started");
+ }
+
+ private void checkInElement() throws IOException {
+ condition(levels.size() > 0, "not in an element");
+ }
+
+ // -- attributes ----------------------------------------------------
+
+ private String[][] attributes;
+
+ private void addAttribute(String name, String value) throws IOException {
+ addAttribute(name, value, false);
+ }
+
+ private void addAttribute(String name, String value, boolean noLines) throws IOException {
+ if (!XMLUtil.isNMToken(name))
+ throw new IOException("XML name "+name+" is not valid for value '"+value+"'");
+
+ newLevelIfRequired();
+ value = XMLUtil.escapeXML(value, charset, noLines);
+
+ if (attributes == null)
+ attributes = new String[][] {{name, value}};
+ else {
+ String[][] newattr = new String[attributes.length+1][];
+ for (int i = 0; i < attributes.length; i++) {
+ condition(!attributes[i][0].equals(name), "attempt to define attribute with name "+name+" more than once for value '"+value+"'");
+ newattr[i] = attributes[i];
+ }
+ attributes = newattr;
+ attributes[attributes.length-1] = new String[] {name, value};
+ }
+ }
+
+ protected String getAttribute(String name) {
+ if (attributes != null) {
+ for (int i = 0; i < attributes.length; i++) {
+ if (attributes[i][0].equals(name)) {
+ return attributes[i][1];
+ }
+ }
+ }
+ return null;
+ }
+
+ protected void setAttribute(String name, String value) throws IOException {
+ newLevelIfRequired();
+ if (attributes == null)
+ addAttribute(name, value, false);
+ else {
+ for (int i = 0; i < attributes.length; i++) {
+ if (attributes[i][0].equals(name)) {
+ attributes[i][1] = XMLUtil.escapeXML(value, charset, false);
+ return;
+ }
+ }
+ addAttribute(name, value);
+ }
+ }
+
+ protected void commitAttributes() throws IOException {
+
+ }
+
+
+ private boolean nameIsSpecial(String name) {
+ for (int i = 0; i < specialAttributeNames.length; i++) {
+ String n = specialAttributeNames[i];
+ if (n.equalsIgnoreCase(name))
+ return true;
+ }
+ return false;
+ }
+
+ private void writeAttributes(int col) throws IOException {
+ commitAttributes();
+ if (attributes != null && sortAttributes)
+ sortAttributes();
+ int c = col;
+ c = writeAttributeSet(true, c, col);
+ writeAttributeSet(false, c, col);
+ attributes = null;
+ }
+
+
+ private void sortAttributes() {
+ // bubble sort - look, it's easy
+ for (int i = 0; i < attributes.length - 1; i++) {
+ for (int j = 0; j < attributes.length - 1; j++) {
+ if (String.CASE_INSENSITIVE_ORDER.compare(attributes[j][0], attributes[j+1][0]) < 0) {
+ String[] t = attributes[j];
+ attributes[j] = attributes[j+1];
+ attributes[j+1] = t;
+ }
+ }
+ }
+
+ }
+
+
+ private int writeAttributeSet(boolean special, int col, int wrap) throws IOException {
+ // first pass: name, id
+ if (attributes != null) {
+ for (int i=0; i < attributes.length; i++) {
+ String[] element = attributes[i];
+ if (nameIsSpecial(element[0]) == special) {
+ col = col + element[0].length()+element[1].length() + 4;
+ if (isPretty() && attributeLineWrap > 0 && col > attributeLineWrap && col > wrap) {
+ write(lineType == LINE_UNIX ? "\n" : "\r\n");
+ for (int j = 0; j < wrap; j++)
+ write(" ");
+ col = wrap;
+ }
+ write(' ');
+ write(element[0]);
+ write("=\"");
+ if (element[1] != null)
+ write(xmlEscape(element[1]));
+ write("\"");
+ }
+ }
+ }
+ return col;
+ }
+
+ protected String xmlEscape(String s) {
+ StringBuilder b = new StringBuilder();
+ for (char c : s.toCharArray()) {
+ if (c < ' ') {
+ b.append("");
+ b.append(Integer.toHexString(c).toUpperCase());
+ b.append(";");
+ } else
+ b.append(c);
+ }
+ return b.toString();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ohf.utilities.xml.IXMLWriter#attribute(java.lang.String, java.lang.String, java.lang.String, boolean)
+ */
+ @Override
+ public void attribute(String namespace, String name, String value, boolean onlyIfNotEmpty) throws IOException {
+ if (!onlyIfNotEmpty || value != null && !value.equals(""))
+ attribute(namespace, name, value);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ohf.utilities.xml.IXMLWriter#attribute(java.lang.String, java.lang.String, java.lang.String)
+ */
+ @Override
+ public void attribute(String namespace, String name, String value) throws IOException {
+
+ checkStarted();
+ if (namespace == null || namespace.equals(""))
+ addAttribute(name, value);
+ else
+ addAttribute(getNSAbbreviation(namespace)+name, value);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ohf.utilities.xml.IXMLWriter#attribute(java.lang.String, java.lang.String, boolean)
+ */
+ @Override
+ public void attribute(String name, String value, boolean onlyIfNotEmpty) throws IOException {
+ if (!onlyIfNotEmpty || value != null && !value.equals(""))
+ attribute(name, value);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ohf.utilities.xml.IXMLWriter#attribute(java.lang.String, java.lang.String)
+ */
+ @Override
+ public void attribute(String name, String value) throws IOException {
+ checkStarted();
+ addAttribute(name, value);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ohf.utilities.xml.IXMLWriter#attributeNoLines(java.lang.String, java.lang.String)
+ */
+ @Override
+ public void attributeNoLines(String name, String value) throws IOException {
+ checkStarted();
+ addAttribute(name, value, true);
+ }
+
+ // -- levels -------------------------------------------------
+
+ private XMLWriterStateStack levels = new XMLWriterStateStack();
+
+ private void newLevelIfRequired() throws IOException {
+ if (!pendingOpen) {
+ if (!levels.empty())
+ levels.current().seeChild();
+ XMLWriterState level = new XMLWriterState();
+ level.setPretty(isPretty());
+ levels.push(level);
+ pendingOpen = true;
+ }
+ }
+
+ // -- namespaces ---------------------------------------------
+
+
+ private void defineNamespace(String namespace, String abbrev) throws IOException {
+ checkStarted();
+ if (namespace != null && !namespace.equals("")) {
+ if ("".equals(abbrev))
+ abbrev = null;
+
+ newLevelIfRequired();
+
+ levels.current().addNamespaceDefn(namespace, abbrev);
+ if (abbrev == null)
+ addAttribute("xmlns", namespace);
+ else
+ addAttribute("xmlns:"+abbrev, namespace);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ohf.utilities.xml.IXMLWriter#findByNamespace(java.lang.String)
+ */
+ public XMLNamespace findByNamespace(String namespace) {
+ for (int i = levels.size() - 1; i >= 0; i--) {
+ XMLNamespace ns = levels.item(i).getDefnByNamespace(namespace);
+ if (ns != null)
+ return ns;
+ }
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ohf.utilities.xml.IXMLWriter#namespaceDefined(java.lang.String)
+ */
+ @Override
+ public boolean namespaceDefined(String namespace) {
+ return namespace == null || namespace.equals("") || findByNamespace(namespace) != null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ohf.utilities.xml.IXMLWriter#findByAbbreviation(java.lang.String)
+ */
+ public XMLNamespace findByAbbreviation(String abbreviation) {
+ for (int i = levels.size() - 1; i >= 0; i--) {
+ XMLNamespace ns = levels.item(i).getDefnByAbbreviation(abbreviation);
+ if (ns != null)
+ return ns;
+ }
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ohf.utilities.xml.IXMLWriter#abbreviationDefined(java.lang.String)
+ */
+ @Override
+ public boolean abbreviationDefined(String abbreviation) {
+ return findByAbbreviation(abbreviation) != null;
+ }
+
+ protected XMLNamespace findDefaultNamespace() {
+ for (int i = levels.size() - 1; i >= 0; i--) {
+ XMLNamespace ns = levels.item(i).getDefaultNamespace();
+ if (ns != null)
+ return ns;
+ }
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ohf.utilities.xml.IXMLWriter#getDefaultNamespace()
+ */
+ @Override
+ public String getDefaultNamespace() {
+ XMLNamespace ns = findDefaultNamespace();
+ if (ns == null)
+ return null;
+ else
+ return ns.getNamespace();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ohf.utilities.xml.IXMLWriter#namespace(java.lang.String)
+ */
+ @Override
+ public void namespace(String namespace) throws IOException {
+ if (!namespaceDefined(namespace)) {
+ int index = 0;
+ while (abbreviationDefined("ns"+Integer.toString(index)))
+ index++;
+ defineNamespace(namespace, "ns"+Integer.toString(index));
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ohf.utilities.xml.IXMLWriter#defaultNamespace(java.lang.String)
+ *
+ * Replace defaultNamespace()
+ */
+ @Override
+ public void setDefaultNamespace(String namespace) throws IOException {
+ if ((namespace == null && getDefaultNamespace() != null) ||
+ (namespace != null && !namespace.equals(getDefaultNamespace())))
+ defineNamespace(namespace, "");
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ohf.utilities.xml.IXMLWriter#namespace(java.lang.String, java.lang.String)
+ */
+ @Override
+ public void namespace(String namespace, String abbreviation) throws IOException {
+ XMLNamespace ns = findByAbbreviation(abbreviation);
+ if (ns == null || !ns.getNamespace().equals(namespace))
+ defineNamespace(namespace, abbreviation);
+ }
+
+
+ private String getNSAbbreviation(String namespace) throws IOException {
+ if ("http://www.w3.org/XML/1998/namespace".equals(namespace))
+ return "xml:";
+
+ if (namespace == null || "".equals(namespace) || "noNamespace".equals(namespace))
+ return "";
+
+ XMLNamespace ns = findByNamespace(namespace);
+ if (ns == null)
+ throw new IOException("Namespace "+namespace+" is not defined");
+ else if (ns.getAbbreviation() == null)
+ return "";
+ else
+ return ns.getAbbreviation()+":";
+ }
+
+ // -- public API -----------------------------------------------------------
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ohf.utilities.xml.IXMLWriter#comment(java.lang.String, boolean)
+ */
+ @Override
+ public void comment(String comment, boolean doPretty) throws IOException {
+ checkStarted();
+ if (pendingClose) {
+ write('>');
+ writePendingComment();
+ pendingClose = false;
+ }
+ if (doPretty) {
+ writePretty();
+ }
+ if (levels.inComment())
+ write(" ");
+ if (doPretty && !isPretty())
+ writePretty();
+ }
+
+
+ private void writePendingComment() throws IOException {
+ if (pendingComment != null) {
+ if (isPretty())
+ write(" ");
+ if (levels.inComment())
+ write("");
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ohf.utilities.xml.IXMLWriter#open(java.lang.String, java.lang.String)
+ */
+ @Override
+ public void enter(String namespace, String name) throws IOException {
+ enter(namespace, name, null);
+ }
+
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ohf.utilities.xml.IXMLWriter#open(java.lang.String, java.lang.String, java.lang.String)
+ */
+ @Override
+ public void enter(String namespace, String name, String comment) throws IOException {
+ if (name == null)
+ throw new Error("name == null");
+ if (!XMLUtil.isNMToken(name))
+ throw new IOException("XML name "+name+" is not valid");
+ checkStarted();
+ if (pendingClose) {
+ write('>');
+ writePendingComment();
+ pendingClose = false;
+ }
+
+ if (name == null) {
+ throw new IOException("name is null");
+ }
+ newLevelIfRequired();
+ levels.current().setName(name);
+ levels.current().setNamespace(namespace);
+ int col = writePretty();
+ write('<');
+ if (namespace == null) {
+ write(name);
+ col = col + name.length()+1;
+ } else {
+ String n = getNSAbbreviation(namespace)+name;
+ write(n);
+ col = col + n.length()+1;
+ }
+ writeAttributes(col);
+ pendingOpen = false;
+ pendingClose = true;
+ pendingComment = comment;
+ }
+
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ohf.utilities.xml.IXMLWriter#close(java.lang.String)
+ */
+ @Override
+ public void exit(String name) throws IOException {
+ checkStarted();
+ if (levels.empty())
+ throw new IOException("Unable to close null|"+name+", nothing to close");
+ if (levels.current().getNamespace() != null || !levels.current().getName().equals(name))
+ throw new IOException("Unable to close null|"+name+", found "+levels.current().getNamespace()+"|"+levels.current().getName());
+ exit();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ohf.utilities.xml.IXMLWriter#close(java.lang.String, java.lang.String)
+ */
+ @Override
+ public void exit(String namespace, String name) throws IOException {
+ checkStarted();
+ if (levels.empty())
+ throw new IOException("Unable to close "+namespace+"|"+name+", nothing to close");
+ if (levels == null)
+ throw new Error("levels = null");
+ if (levels.current() == null)
+ throw new Error("levels.current() = null");
+ if (levels.current().getName() == null)
+ throw new Error("levels.current().getName() = null");
+ if (levels.current().getNamespace() == null)
+ throw new Error("levels.current().getNamespace() = null");
+ if (name == null)
+ throw new Error("name = null");
+ if (namespace == null)
+ throw new Error("namespace = null");
+ if (!levels.current().getNamespace().equals(namespace) || !levels.current().getName().equals(name))
+ throw new IOException("Unable to close "+namespace+"|"+name+", found "+levels.current().getNamespace()+"|"+levels.current().getName());
+ exit();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ohf.utilities.xml.IXMLWriter#closeToLevel(int)
+ */
+ @Override
+ public void exitToLevel(int count) throws IOException {
+ checkStarted();
+ while (levels.size() > count)
+ exit();
+ }
+
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ohf.utilities.xml.IXMLWriter#close()
+ */
+ @Override
+ public void close() throws IOException {
+ checkStarted();
+ if (!levels.empty())
+ throw new IOException("Called close before exiting all opened elements");
+ super.close();
+ }
+
+ @Override
+ public void end() throws IOException {
+ checkStarted();
+ if (!levels.empty())
+ throw new IOException("Called end() before exiting all opened elements");
+ flush();
+ }
+ @Override
+ public void exit() throws IOException {
+ checkStarted();
+ if (levels.empty()) {
+ throw new IOException("Called exit one too many times");
+ } else {
+ if (pendingClose) {
+ write("/>");
+ writePendingComment();
+ pendingClose = false;
+ } else {
+ if (levels.current().hasChildren())
+ writePretty();
+ write("");
+ if (levels.current().getNamespace() == null)
+ write(levels.current().getName());
+ else
+ write(getNSAbbreviation(levels.current().getNamespace())+levels.current().getName());
+ write('>');
+ }
+ levels.pop();
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ohf.utilities.xml.IXMLWriter#open(java.lang.String)
+ */
+ @Override
+ public void enter(String name) throws IOException {
+ enter(null, name);
+ }
+
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ohf.utilities.xml.IXMLWriter#element(java.lang.String, java.lang.String, java.lang.String, boolean)
+ */
+ @Override
+ public void element(String namespace, String name, String content, boolean onlyIfNotEmpty) throws IOException {
+ if (!onlyIfNotEmpty || content != null && !content.equals(""))
+ element(namespace, name, content);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ohf.utilities.xml.IXMLWriter#element(java.lang.String, java.lang.String, java.lang.String, java.lang.String)
+ */
+ @Override
+ public void element(String namespace, String name, String content, String comment) throws IOException {
+ if (!XMLUtil.isNMToken(name))
+ throw new IOException("XML name "+name+" is not valid");
+ enter(namespace, name, comment);
+ text(content);
+ exit();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ohf.utilities.xml.IXMLWriter#element(java.lang.String, java.lang.String, java.lang.String)
+ */
+ @Override
+ public void element(String namespace, String name, String content) throws IOException {
+ if (!XMLUtil.isNMToken(name))
+ throw new IOException("XML name "+name+" is not valid");
+ enter(namespace, name);
+ text(content);
+ exit();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ohf.utilities.xml.IXMLWriter#element(java.lang.String, java.lang.String, boolean)
+ */
+ @Override
+ public void element(String name, String content, boolean onlyIfNotEmpty) throws IOException {
+ if (!onlyIfNotEmpty || content != null && !content.equals(""))
+ element(null, name, content);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ohf.utilities.xml.IXMLWriter#element(java.lang.String, java.lang.String)
+ */
+ @Override
+ public void element(String name, String content) throws IOException {
+ element(null, name, content);
+ }
+
+ @Override
+ public void element(String name) throws IOException {
+ element(null, name, null);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ohf.utilities.xml.IXMLWriter#text(java.lang.String)
+ */
+ @Override
+ public void text(String content) throws IOException {
+ text(content, false);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ohf.utilities.xml.IXMLWriter#text(java.lang.String, boolean)
+ *
+ * Replace escapeText()
+ */
+ @Override
+ public void text(String content, boolean dontEscape) throws IOException {
+ checkInElement();
+ if (content != null) {
+ if (pendingClose) {
+ write(">");
+ writePendingComment();
+ pendingClose = false;
+ }
+ if (dontEscape)
+ write(content);
+ else
+ write(XMLUtil.escapeXML(content, charset, false));
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ohf.utilities.xml.IXMLWriter#cData(java.lang.String)
+ */
+ @Override
+ public void cData(String text) throws IOException {
+ text("");
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ohf.utilities.xml.IXMLWriter#writeBytes(byte[])
+ */
+ @Override
+ public void writeBytes(byte[] bytes) throws IOException {
+ checkInElement();
+ if (pendingClose) {
+ write(">");
+ writePendingComment();
+ pendingClose = false;
+ }
+ flush();
+ stream.write(bytes);
+ }
+
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ohf.utilities.xml.IXMLWriter#isPretty()
+ */
+ @Override
+ public boolean isPretty() throws IOException {
+ return (levels == null || levels.empty()) ? prettyBase : levels.current().isPretty();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ohf.utilities.xml.IXMLWriter#setPretty(boolean)
+ */
+ @Override
+ public void setPretty(boolean pretty) throws IOException {
+ if (levels == null || levels.empty())
+ this.prettyBase = pretty;
+ else
+ levels.current().setPretty(pretty);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ohf.utilities.xml.IXMLWriter#startCommentBlock()
+ */
+ @Override
+ public void startCommentBlock() throws IOException {
+ if (levels.inComment())
+ throw new IOException("cannot nest comments");
+ levels.current().setInComment(true);
+ if (isPretty())
+ writePretty();
+ write("");
+ if (isPretty())
+ writePretty();
+ levels.current().setInComment(false);
+ }
+
+ public boolean isSortAttributes() {
+ return sortAttributes;
+ }
+
+ public void setSortAttributes(boolean sortAttributes) {
+ this.sortAttributes = sortAttributes;
+ }
+
+
+ public boolean isPrettyHeader() {
+ return prettyHeader;
+ }
+
+ public void setPrettyHeader(boolean pretty) {
+ this.prettyHeader = pretty;
+ }
+
+ public int writePretty() throws IOException {
+ return writePretty(true);
+ }
+
+ public int writePretty(boolean eoln) throws IOException {
+ if (isPretty()) {
+ if (eoln)
+ write(lineType == LINE_UNIX ? "\n" : "\r\n");
+ for (int i = 0; i < levels.size() - 1; i++)
+ write(" ");
+ return (levels.size() - 1) * 2;
+ } else
+ return 0;
+ }
+
+ public int getLineType() {
+ return lineType;
+ }
+
+ public void setLineType(int lineType) {
+ this.lineType = lineType;
+ }
+
+ public boolean isXmlHeader() {
+ return xmlHeader;
+ }
+
+ public void setXmlHeader(boolean xmlHeader) {
+ this.xmlHeader = xmlHeader;
+ }
+
+ public String[] getSpecialAttributeNames() {
+ return specialAttributeNames;
+ }
+
+ public void setSpecialAttributeNames(String[] specialAttributeNames) {
+ this.specialAttributeNames = specialAttributeNames;
+ }
+
+ public int getAttributeLineWrap() {
+ return attributeLineWrap;
+ }
+
+ public void setAttributeLineWrap(int attributeLineWrap) {
+ this.attributeLineWrap = attributeLineWrap;
+ }
+
+ @Override
+ public void escapedText(String content) throws IOException {
+ text("");
+ int i = content.length();
+ if (isPretty())
+ while (i > 0 && (content.charAt(i-1) == '\r' || content.charAt(i-1) == '\n'))
+ i--;
+ write(content.substring(0, i));
+ }
+
+ public void processingInstruction(String value) throws IOException {
+ write(""+value+"?>");
+ if (isPrettyHeader())
+ write("\r\n");
+ }
+
+ @Override
+ public void link(String href) {
+ // ignore this
+
+ }
+
+ @Override
+ public void anchor(String name) {
+ // ignore this
+ }
+
+ @Override
+ public void decorate(ElementDecoration element) throws IOException {
+ // nothing...
+ }
+ @Override
+ public void setSchemaLocation(String ns, String loc) throws IOException {
+ namespace("http://www.w3.org/2001/XMLSchema-instance", "xsi");
+ attribute("http://www.w3.org/2001/XMLSchema-instance", "schemaLocation", ns+" "+loc);
+
+ }
+ @Override
+ public void externalLink(String ref) {
+ // ignore this
+ }
+
+ @Override
+ public boolean canElide() { return false; }
+
+ @Override
+ public void attributeElide() {
+ // ignore this
+ }
+
+ @Override
+ public void elide() throws IOException {
+ // ignore this
+ }
+
}
\ No newline at end of file
diff --git a/org.hl7.fhir.utilities/src/main/resources/Messages.properties b/org.hl7.fhir.utilities/src/main/resources/Messages.properties
index 35811c33e..4c4e156d9 100644
--- a/org.hl7.fhir.utilities/src/main/resources/Messages.properties
+++ b/org.hl7.fhir.utilities/src/main/resources/Messages.properties
@@ -13,7 +13,9 @@ Attempt_to_a_slice_an_element_that_does_not_repeat__from__in_ = Attempt to a sli
Attempt_to_replace_element_name_for_a_nonchoice_type=Attempt to replace element name for a non-choice type
Attempt_to_use_Terminology_server_when_no_Terminology_server_is_available = Attempt to use Terminology server when no Terminology server is available
Attempt_to_use_a_snapshot_on_profile__as__before_it_is_generated = Attempt to use a snapshot on profile ''{0}'' as {1} before it is generated
-BINDING_ADDITIONAL = {0} specified in an additional binding
+BINDING_ADDITIONAL_D = {0} specified in an additional binding
+BINDING_ADDITIONAL_UC = {0} specified in an additional binding which applies because {1}
+BINDING_ADDITIONAL_USAGE = {0} = {1}
BINDING_MAX = {0} specified in the max binding
BUNDLE_BUNDLE_ENTRY_FOUND_MULTIPLE = Found {0} matches for ''{1}'' in the bundle ({2})
BUNDLE_BUNDLE_ENTRY_FOUND_MULTIPLE_FRAGMENT = Found {0} matches for fragment {2} in resource ''{1}'' in the bundle ({3})
@@ -1029,7 +1031,7 @@ VALUESET_SUPPLEMENT_MISSING_one = Required supplement not found: {1}
VALUESET_SUPPLEMENT_MISSING_other = Required supplements not found: {1}
VALUESET_TOO_COSTLY = The value set ''{0}'' expansion has too many codes to display ({1})
VALUESET_TOO_COSTLY_COUNT = The value set ''{0}'' expansion has {2} codes, which is too many to display ({1})
-VALUESET_TOO_COSTLY_TIME = The value set ''{0}'' expansion took too long to process (>{1}sec)
+VALUESET_TOO_COSTLY_TIME = The value set ''{0}'' {2} took too long to process (>{1}sec)
VALUESET_UNC_SYSTEM_WARNING = Unknown System ''{0}'' specified, so Concepts and Filters can''t be checked (Details: {1})
VALUESET_UNC_SYSTEM_WARNING_VER = Unknown System/Version ''{0}'' specified, so Concepts and Filters can''t be checked (Details: {1})
VALUESET_UNKNOWN_FILTER_PROPERTY = The property ''{0}'' is not known for the system ''{1}'', so may not be understood by the terminology ecosystem. Known properties for this system: {2}
@@ -1138,8 +1140,12 @@ TYPE_SPECIFIC_CHECKS_DT_XHTML_LITERAL_HREF = Hyperlink scheme ''{3}'' in ''{0}''
SM_TARGET_TYPE_UNKNOWN = The type of the target variable is not known: {0}
XHTML_XHTML_ATTRIBUTE_XML_SPACE = The attribute 'xml:space' is legal but has a fixed value of 'preserve'. It''s use is discouraged
VALIDATION_HL7_PUBLISHER_MULTIPLE_WGS = This resource has more than workgroup extension (http://hl7.org/fhir/StructureDefinition/structuredefinition-wg)
-NO_VALID_DISPLAY_FOUND_NONE_FOR_LANG = Wrong Display Name ''{0}'' for {1}#{2}. There are no valid display names found for language(s) ''{3}''. Default display is ''{4}''
+NO_VALID_DISPLAY_FOUND_NONE_FOR_LANG_OK = There are no valid display names found for the code {1}#{2} for language(s) ''{3}''. The display is ''{4}'' the default language display
+NO_VALID_DISPLAY_FOUND_NONE_FOR_LANG_ERR = Wrong Display Name ''{0}'' for {1}#{2}. There are no valid display names found for language(s) ''{3}''. Default display is ''{4}''
NO_VALID_DISPLAY_AT_ALL = Cannot validate display Name ''{0}'' for {1}#{2}: No displays are known
SD_BASE_EXPERIMENTAL = The definition builds on ''{0}'' which is experimental, but this definition is not labeled as experimental
SD_ED_EXPERIMENTAL_BINDING = The definition for the element ''{0}'' binds to the value set ''{1}'' which is experimental, but this structure is not labeled as experimental
VALIDATION_NO_EXPERIMENTAL_CONTENT = Experimental content is not allowed in this context
+SD_ED_ADDITIONAL_BINDING_USAGE_UNKNOWN = The Usage Context {0}#{1} is not recognised and may not be correct
+SD_ED_ADDITIONAL_BINDING_USAGE_INVALID_ELEMENT = The Usage Context {0}#{1} is a reference to an element that does not exist
+SD_ED_ADDITIONAL_BINDING_USAGE_INVALID_TYPE = The Usage Context value must be of type {1} not {0}
diff --git a/org.hl7.fhir.utilities/src/main/resources/rendering-phrases.properties b/org.hl7.fhir.utilities/src/main/resources/rendering-phrases.properties
index 0147ecbe4..39aa5cab8 100644
--- a/org.hl7.fhir.utilities/src/main/resources/rendering-phrases.properties
+++ b/org.hl7.fhir.utilities/src/main/resources/rendering-phrases.properties
@@ -207,7 +207,8 @@ DATA_REND_COND = Condition
DATA_REND_COUNT = Count {0}
DATA_REND_DATA = Data: {0}
DATA_REND_DETAILS = (Details: {0} code
-DATA_REND_DETAILS_STATED = (Details: {0} code {1} {2} {3} '', stated as '' {4} {5}
+DATA_REND_DETAILS_STATED = (Details: {0} code {1} = ''{2}'')
+DATA_REND_DETAILS_STATED_ND = (Details: {0} code {1})
DATA_REND_DICOM = DICOM
DATA_REND_DIM = Dimensions: {0}
DATA_REND_DURATION = Duration {0}
diff --git a/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/npm/FilesystemPackageManagerLockTests.java b/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/npm/FilesystemPackageManagerLockTests.java
index f1d71dda3..8fa981d88 100644
--- a/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/npm/FilesystemPackageManagerLockTests.java
+++ b/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/npm/FilesystemPackageManagerLockTests.java
@@ -1,7 +1,7 @@
package org.hl7.fhir.utilities.npm;
-import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.filesystem.ManagedFileAccess;
+import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -12,10 +12,12 @@ import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.assertTrue;
import static org.junit.jupiter.api.Assertions.assertThrows;
public class FilesystemPackageManagerLockTests {
@@ -49,13 +51,13 @@ public class FilesystemPackageManagerLockTests {
packageLock.doWriteWithLock(() -> {
assertThat(packageLock.getLockFile()).exists();
return null;
- });
+ }, null);
assertThat(packageLock.getLockFile()).doesNotExist();
packageLock.doReadWithLock(() -> {
assertThat(packageLock.getLockFile()).doesNotExist();
return null;
- });
+ }, null);
}
@Test void testNoPackageWriteOrReadWhileWholeCacheIsLocked() throws IOException, InterruptedException {
@@ -87,7 +89,7 @@ public class FilesystemPackageManagerLockTests {
packageLock.doWriteWithLock(() -> {
assertThat(cacheLockFinished.get()).isTrue();
return null;
- });
+ }, null);
} catch (IOException e) {
throw new RuntimeException(e);
}
@@ -97,7 +99,7 @@ public class FilesystemPackageManagerLockTests {
packageLock.doReadWithLock(() -> {
assertThat(cacheLockFinished.get()).isTrue();
return null;
- });
+ }, null);
} catch (IOException e) {
throw new RuntimeException(e);
}
@@ -116,6 +118,23 @@ public class FilesystemPackageManagerLockTests {
}
}
+ @Test void testWhenLockIsntHeld_canLockFileBeHeldByThisProcessIsTrue() throws IOException {
+ File lockFile = getPackageLockFile();
+ lockFile.createNewFile();
+ Assertions.assertTrue(filesystemPackageCacheLockManager.getCacheLock().canLockFileBeHeldByThisProcess(lockFile));
+ }
+
+ @Test void testWhenLockIsHelp_canLockFileBeHeldByThisProcessIsFalse() throws InterruptedException, TimeoutException, IOException {
+ File lockFile = getPackageLockFile();
+ Thread lockThread = LockfileTestProcessUtility.lockWaitAndDeleteInNewProcess(cachePath, DUMMY_PACKAGE + ".lock", 2);
+
+ LockfileTestUtility.waitForLockfileCreation(cacheDirectory.getAbsolutePath(), DUMMY_PACKAGE + ".lock");
+
+ Assertions.assertFalse(filesystemPackageCacheLockManager.getCacheLock().canLockFileBeHeldByThisProcess(lockFile));
+
+ lockThread.join();
+ }
+
@Test void testSinglePackageWriteMultiPackageRead() throws IOException {
final FilesystemPackageCacheManagerLocks.PackageLock packageLock = filesystemPackageCacheLockManager.getPackageLock(DUMMY_PACKAGE);
AtomicInteger writeCounter = new AtomicInteger(0);
@@ -133,7 +152,7 @@ public class FilesystemPackageManagerLockTests {
assertThat(writeCount).isEqualTo(1);
writeCounter.decrementAndGet();
return null;
- });
+ }, null);
} catch (IOException e) {
throw new RuntimeException(e);
}
@@ -156,7 +175,7 @@ public class FilesystemPackageManagerLockTests {
}
readCounter.decrementAndGet();
return null;
- });
+ }, null);
} catch (IOException e) {
throw new RuntimeException(e);
}
@@ -179,49 +198,47 @@ public class FilesystemPackageManagerLockTests {
}
@Test
- public void testReadWhenLockedByFileTimesOut() throws IOException {
- FilesystemPackageCacheManagerLocks shorterTimeoutManager = filesystemPackageCacheLockManager.withLockTimeout(3L, TimeUnit.SECONDS);
+ public void testReadWhenLockedByFileTimesOut() throws InterruptedException, TimeoutException, IOException {
+ FilesystemPackageCacheManagerLocks shorterTimeoutManager = filesystemPackageCacheLockManager;
final FilesystemPackageCacheManagerLocks.PackageLock packageLock = shorterTimeoutManager.getPackageLock(DUMMY_PACKAGE);
- File lockFile = createPackageLockFile();
+ File lockFile = getPackageLockFile();
+ Thread lockThread = LockfileTestProcessUtility.lockWaitAndDeleteInNewProcess(cachePath, lockFile.getName(), 5);
+ LockfileTestUtility.waitForLockfileCreation(cachePath,lockFile.getName());
Exception exception = assertThrows(IOException.class, () -> {
packageLock.doReadWithLock(() -> {
assertThat(lockFile).exists();
return null;
- });
+ }, new FilesystemPackageCacheManagerLocks.LockParameters(3L, TimeUnit.SECONDS));
});
- assertThat(exception.getMessage()).contains("Error reading package");
+ assertThat(exception.getMessage()).contains("Package cache timed out waiting for lock");
assertThat(exception.getCause().getMessage()).contains("Timeout waiting for lock file deletion: " + lockFile.getName());
+
+ lockThread.join();
}
- @Test
- public void testReadWhenLockFileIsDeleted() throws IOException {
- FilesystemPackageCacheManagerLocks shorterTimeoutManager = filesystemPackageCacheLockManager.withLockTimeout(5L, TimeUnit.SECONDS);
- final FilesystemPackageCacheManagerLocks.PackageLock packageLock = shorterTimeoutManager.getPackageLock(DUMMY_PACKAGE);
- File lockFile = createPackageLockFile();
- Thread t = new Thread(() -> {
- try {
- Thread.sleep(2000);
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- }
- lockFile.delete();
- });
- t.start();
+ @Test
+ public void testReadWhenLockFileIsDeleted() throws InterruptedException, TimeoutException, IOException {
+
+ final FilesystemPackageCacheManagerLocks.PackageLock packageLock = filesystemPackageCacheLockManager.getPackageLock(DUMMY_PACKAGE);
+
+ final File lockFile = getPackageLockFile();
+
+ Thread lockThread = LockfileTestProcessUtility.lockWaitAndDeleteInNewProcess(cachePath, lockFile.getName(), 5);
+ LockfileTestUtility.waitForLockfileCreation(cachePath,lockFile.getName());
packageLock.doReadWithLock(() -> {
assertThat(lockFile).doesNotExist();
return null;
- });
+ }, new FilesystemPackageCacheManagerLocks.LockParameters(10L, TimeUnit.SECONDS));
+ lockThread.join();
}
- private File createPackageLockFile() throws IOException {
- File lockFile = Path.of(cachePath, DUMMY_PACKAGE + ".lock").toFile();
- TextFile.stringToFile("", lockFile);
- return lockFile;
+ private File getPackageLockFile() {
+ return Path.of(cachePath, DUMMY_PACKAGE + ".lock").toFile();
}
}
diff --git a/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/npm/FilesystemPackageManagerTests.java b/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/npm/FilesystemPackageManagerTests.java
index eba7b198a..1221aeb66 100644
--- a/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/npm/FilesystemPackageManagerTests.java
+++ b/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/npm/FilesystemPackageManagerTests.java
@@ -2,6 +2,7 @@ package org.hl7.fhir.utilities.npm;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import java.io.File;
@@ -13,6 +14,8 @@ import java.util.List;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Stream;
@@ -20,6 +23,7 @@ import javax.annotation.Nonnull;
import org.hl7.fhir.utilities.IniFile;
import org.hl7.fhir.utilities.filesystem.ManagedFileAccess;
+import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.DisabledOnOs;
import org.junit.jupiter.api.condition.EnabledOnOs;
@@ -113,6 +117,97 @@ public class FilesystemPackageManagerTests {
assertEquals( System.getenv("ProgramData") + "\\.fhir\\packages", folder.getAbsolutePath());
}
+ @Test
+ public void testCorruptPackageCleanup() throws IOException {
+ File cacheDirectory = ManagedFileAccess.fromPath(Files.createTempDirectory("fpcm-multithreadingTest"));
+
+ File dummyPackage = createDummyPackage(cacheDirectory, "example.fhir.uv.myig", "1.2.3");
+ File dummyLockFile = createDummyLockFile(cacheDirectory, "example.fhir.uv.myig" , "1.2.3");
+
+ assertThat(dummyPackage).isDirectory();
+ assertThat(dummyPackage).exists();
+ assertThat(dummyLockFile).exists();
+
+ FilesystemPackageCacheManager filesystemPackageCacheManager = new FilesystemPackageCacheManager.Builder().withCacheFolder(cacheDirectory.getAbsolutePath()).build();
+
+ assertThat(dummyPackage).doesNotExist();
+ assertThat(dummyLockFile).doesNotExist();
+ }
+
+ @Test
+ public void testLockedPackageIsntCleanedUp() throws IOException, InterruptedException, TimeoutException {
+ File cacheDirectory = ManagedFileAccess.fromPath(Files.createTempDirectory("fpcm-multithreadingTest"));
+
+ File dummyPackage = createDummyPackage(cacheDirectory, "example.fhir.uv.myig", "1.2.3");
+
+ Thread lockThread = LockfileTestProcessUtility.lockWaitAndDeleteInNewProcess(cacheDirectory.getAbsolutePath(), "example.fhir.uv.myig#1.2.3.lock", 2);
+
+ LockfileTestUtility.waitForLockfileCreation(cacheDirectory.getAbsolutePath(), "example.fhir.uv.myig#1.2.3.lock");
+ File dummyLockFile = ManagedFileAccess.file(cacheDirectory.getAbsolutePath(), "example.fhir.uv.myig#1.2.3.lock");
+
+ assertThat(dummyPackage).isDirectory();
+ assertThat(dummyPackage).exists();
+ assertThat(dummyLockFile).exists();
+
+ FilesystemPackageCacheManager filesystemPackageCacheManager = new FilesystemPackageCacheManager.Builder().withCacheFolder(cacheDirectory.getAbsolutePath()).build();
+
+ assertThat(dummyPackage).exists();
+ assertThat(dummyLockFile).exists();
+
+ lockThread.join();
+ }
+
+ @Test
+ public void testTimeoutForLockedPackageRead() throws IOException, InterruptedException, TimeoutException {
+ String pcmPath = ManagedFileAccess.fromPath(Files.createTempDirectory("fpcm-multithreadingTest")).getAbsolutePath();
+
+ final FilesystemPackageCacheManager pcm = new FilesystemPackageCacheManager.Builder()
+ .withCacheFolder(pcmPath)
+ .withLockParameters(new FilesystemPackageCacheManagerLocks.LockParameters(5,TimeUnit.SECONDS))
+ .build();
+
+ Assertions.assertTrue(pcm.listPackages().isEmpty());
+
+ Thread lockThread = LockfileTestProcessUtility.lockWaitAndDeleteInNewProcess(pcmPath, "example.fhir.uv.myig#1.2.3.lock", 10);
+ File directory = ManagedFileAccess.file(pcmPath, "example.fhir.uv.myig#1.2.3" );
+ directory.mkdir();
+
+ LockfileTestUtility.waitForLockfileCreation(pcmPath, "example.fhir.uv.myig#1.2.3.lock");
+
+ IOException exception = assertThrows(IOException.class, () -> pcm.loadPackageFromCacheOnly("example.fhir.uv.myig", "1.2.3"));
+
+ assertThat(exception.getMessage()).contains("Package cache timed out waiting for lock");
+ assertThat(exception.getCause().getMessage()).contains("Timeout waiting for lock file deletion");
+ lockThread.join();
+ }
+
+ @Test
+ public void testReadFromCacheOnlyWaitsForLockDelete() throws IOException, InterruptedException, TimeoutException {
+ String pcmPath = ManagedFileAccess.fromPath(Files.createTempDirectory("fpcm-multithreadingTest")).getAbsolutePath();
+
+ final FilesystemPackageCacheManager pcm = new FilesystemPackageCacheManager.Builder().withCacheFolder(pcmPath).build();
+
+ Assertions.assertTrue(pcm.listPackages().isEmpty());
+
+ pcm.addPackageToCache("example.fhir.uv.myig", "1.2.3", this.getClass().getResourceAsStream("/npm/dummy-package.tgz"), "https://packages.fhir.org/example.fhir.uv.myig/1.2.3");
+
+ String packageAndVersion = "example.fhir.uv.myig#1.2.3";
+
+ //Now sneak in a new lock file and directory:
+
+ File directory = ManagedFileAccess.file(pcmPath, packageAndVersion);
+ directory.mkdir();
+
+ Thread lockThread = LockfileTestProcessUtility.lockWaitAndDeleteInNewProcess(pcmPath, "example.fhir.uv.myig#1.2.3.lock", 5);
+ LockfileTestUtility.waitForLockfileCreation(pcmPath, "example.fhir.uv.myig#1.2.3.lock");
+
+ NpmPackage npmPackage = pcm.loadPackageFromCacheOnly("example.fhir.uv.myig", "1.2.3");
+
+ assertThat(npmPackage.id()).isEqualTo("example.fhir.uv.myig");
+
+ lockThread.join();
+ }
+
/**
We repeat the same tests multiple times here, in order to catch very rare edge cases.
*/
@@ -126,16 +221,16 @@ public class FilesystemPackageManagerTests {
return params.stream();
}
- private void createDummyTemp(File cacheDirectory, String lowerCase) throws IOException {
- createDummyPackage(cacheDirectory, lowerCase);
+ private File createDummyTemp(File cacheDirectory, String lowerCase) throws IOException {
+ return createDummyPackage(cacheDirectory, lowerCase);
}
- private void createDummyPackage(File cacheDirectory, String packageName, String packageVersion) throws IOException {
+ private File createDummyPackage(File cacheDirectory, String packageName, String packageVersion) throws IOException {
String directoryName = packageName + "#" + packageVersion;
- createDummyPackage(cacheDirectory, directoryName);
+ return createDummyPackage(cacheDirectory, directoryName);
}
- private static void createDummyPackage(File cacheDirectory, String directoryName) throws IOException {
+ private static File createDummyPackage(File cacheDirectory, String directoryName) throws IOException {
File packageDirectory = ManagedFileAccess.file(cacheDirectory.getAbsolutePath(), directoryName);
packageDirectory.mkdirs();
@@ -144,6 +239,16 @@ public class FilesystemPackageManagerTests {
wr.write("Ain't nobody here but us chickens");
wr.flush();
wr.close();
+ return packageDirectory;
+ }
+
+ private File createDummyLockFile(File cacheDirectory, String packageName, String packageVersion) throws IOException {
+ final File dummyLockFile = ManagedFileAccess.file(cacheDirectory.getAbsolutePath(), packageName + "#" + packageVersion + ".lock");
+ final FileWriter wr = new FileWriter(dummyLockFile);
+ wr.write("Ain't nobody here but us chickens");
+ wr.flush();
+ wr.close();
+ return dummyLockFile;
}
private void assertThatDummyTempExists(File cacheDirectory, String dummyTempPackage) throws IOException {
@@ -241,13 +346,13 @@ public class FilesystemPackageManagerTests {
@MethodSource("packageCacheMultiThreadTestParams")
@ParameterizedTest
public void packageCacheMultiThreadTest(final int threadTotal, final int packageCacheManagerTotal) throws IOException {
-
String pcmPath = ManagedFileAccess.fromPath(Files.createTempDirectory("fpcm-multithreadingTest")).getAbsolutePath();
+ System.out.println("Using temp pcm path: " + pcmPath);
FilesystemPackageCacheManager[] packageCacheManagers = new FilesystemPackageCacheManager[packageCacheManagerTotal];
Random rand = new Random();
final AtomicInteger totalSuccessful = new AtomicInteger();
- final ConcurrentHashMap successfulThreads = new ConcurrentHashMap();
+ final ConcurrentHashMap successfulThreads = new ConcurrentHashMap<>();
List threads = new ArrayList<>();
for (int i = 0; i < threadTotal; i++) {
final int index = i;
@@ -256,22 +361,27 @@ public class FilesystemPackageManagerTests {
System.out.println("Thread #" + index + ": " + Thread.currentThread().getId() + " started");
final int randomPCM = rand.nextInt(packageCacheManagerTotal);
final int randomOperation = rand.nextInt(4);
+ final String operationName;
if (packageCacheManagers[randomPCM] == null) {
packageCacheManagers[randomPCM] = new FilesystemPackageCacheManager.Builder().withCacheFolder(pcmPath).build();
}
FilesystemPackageCacheManager pcm = packageCacheManagers[randomPCM];
if (randomOperation == 0) {
+ operationName = "addPackageToCache";
pcm.addPackageToCache("example.fhir.uv.myig", "1.2.3", this.getClass().getResourceAsStream("/npm/dummy-package.tgz"), "https://packages.fhir.org/example.fhir.uv.myig/1.2.3");
} else if (randomOperation == 1) {
+ operationName = "clear";
pcm.clear();
} else if (randomOperation == 2) {
+ operationName = "loadPackageFromCacheOnly";
pcm.loadPackageFromCacheOnly("example.fhir.uv.myig", "1.2.3");
} else {
+ operationName = "removePackage";
pcm.removePackage("example.fhir.uv.myig", "1.2.3");
}
totalSuccessful.incrementAndGet();
successfulThreads.put(Thread.currentThread().getId(), index);
- System.out.println("Thread #" + index + ": " + Thread.currentThread().getId() + " completed");
+ System.out.println("Thread #" + index + ": " + Thread.currentThread().getId() + " completed. Ran: " + operationName);
} catch (Exception e) {
e.printStackTrace();
System.err.println("Thread #" + index + ": " + Thread.currentThread().getId() + " failed");
diff --git a/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/npm/LockfileTestProcessUtility.java b/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/npm/LockfileTestProcessUtility.java
new file mode 100644
index 000000000..d8f054f3d
--- /dev/null
+++ b/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/npm/LockfileTestProcessUtility.java
@@ -0,0 +1,122 @@
+package org.hl7.fhir.utilities.npm;
+
+import org.hl7.fhir.utilities.filesystem.ManagedFileAccess;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.channels.FileLock;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Paths;
+
+/**
+ * FilesystemPackageCacheManagerLocks relies on the existence of .lock files to prevent access to packages being written
+ * by processes outside the current JVM. Testing this functionality means creating a process outside the JUnit test JVM,
+ * which is achieved by running a separate Java process.
+ *
+ * Intended usage:
+ *
+ * The helper method {@link #lockWaitAndDeleteInNewProcess(String, String, int)} is the intended starting point for
+ * using this class.
+ *
+ *
+ *
+ * This class deliberately avoids using any dependencies outside java.*, which avoids having to construct a classpath
+ * for the separate process.
+ */
+public class LockfileTestProcessUtility {
+ /**
+ * Main method to allow running this class.
+ *
+ * This method calls the {@link #main(String[])} method in a new process.
+ *
+ * @param path The path to create the lockfile in
+ * @param lockFileName The name of the lockfile
+ * @param seconds The number of seconds to wait before deleting the lockfile
+ * @return The thread wrapping the process execution. This can be used to wait for the process to complete, so that
+ * System.out and System.err can be processed before tests return results.
+ */
+ public static Thread lockWaitAndDeleteInNewProcess(String path, String lockFileName, int seconds) {
+ Thread t = new Thread(() -> {
+ ProcessBuilder processBuilder = new ProcessBuilder("java", "-cp", "target/test-classes", LockfileTestProcessUtility.class.getName(), path, lockFileName, Integer.toString(seconds));
+ try {
+ Process process = processBuilder.start();
+ process.getErrorStream().transferTo(System.err);
+ process.getInputStream().transferTo(System.out);
+ process.waitFor();
+ } catch (IOException | InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ });
+ t.start();
+ return t;
+ }
+
+ /**
+ * The actual logic to create a .lock file.
+ *
+ * This should match the logic in FilesystemPackageCacheManagerLocks
+ *
+ *
+ * @param path The path to create the lockfile in
+ * @param lockFileName The name of the lockfile
+ * @param seconds The number of seconds to wait before deleting the lockfile
+ * @throws InterruptedException If the thread is interrupted while waiting
+ * @throws IOException If there is an error accessing the file system
+ */
+ /* TODO Eventually, this logic should exist in a Lockfile class so that it isn't duplicated between the main code and
+ the test code.
+ */
+ private static void lockWaitAndDelete(String path, String lockFileName, int seconds) throws InterruptedException, IOException {
+
+ File lockFile = Paths.get(path,lockFileName).toFile();
+
+ try (FileChannel channel = new RandomAccessFile(lockFile.getAbsolutePath(), "rw").getChannel()) {
+ FileLock fileLock = channel.tryLock(0, Long.MAX_VALUE, false);
+ if (fileLock != null) {
+ final ByteBuffer buff = ByteBuffer.wrap("Hello world".getBytes(StandardCharsets.UTF_8));
+ channel.write(buff);
+ System.out.println("File "+lockFileName+" is locked. Waiting for " + seconds + " seconds to release. ");
+ Thread.sleep(seconds * 1000L);
+
+ lockFile.renameTo(ManagedFileAccess.file(File.createTempFile(lockFile.getName(), ".lock-renamed").getAbsolutePath()));
+
+ fileLock.release();
+ channel.close();
+ System.out.println(System.currentTimeMillis());
+ System.out.println("File "+lockFileName+" is released.");
+
+ lockFile.delete();
+ }}finally {
+ if (lockFile.exists()) {
+ lockFile.delete();
+ }
+ }
+ }
+}
diff --git a/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/npm/LockfileTestUtility.java b/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/npm/LockfileTestUtility.java
new file mode 100644
index 000000000..250e7bcb1
--- /dev/null
+++ b/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/npm/LockfileTestUtility.java
@@ -0,0 +1,78 @@
+package org.hl7.fhir.utilities.npm;
+
+
+import org.apache.commons.io.monitor.FileAlterationListenerAdaptor;
+import org.apache.commons.io.monitor.FileAlterationMonitor;
+import org.apache.commons.io.monitor.FileAlterationObserver;
+
+import java.io.*;
+
+import java.nio.file.*;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+
+public class LockfileTestUtility {
+
+
+
+ /**
+ * Wait for the lock file to be created in the given path.
+ *
+ * Normally, within the same JVM, you could use a CountdownLatch for the same purpose, but since this the lock file is
+ * being created in a separate process, we need to use a mechanism that doesn't rely on shared threads.
+ *
+ * @param path The path containing the lock file
+ * @param lockFileName The name of the lock file
+ * @throws InterruptedException If the thread is interrupted while waiting
+ * @throws TimeoutException If the lock file is not created within 10 seconds
+ */
+ public static void waitForLockfileCreation(String path, String lockFileName) throws InterruptedException, TimeoutException {
+
+ CountDownLatch latch = new CountDownLatch(1);
+ FileAlterationMonitor monitor = new FileAlterationMonitor(100);
+ FileAlterationObserver observer = new FileAlterationObserver(path);
+
+ observer.addListener(new FileAlterationListenerAdaptor(){
+
+ @Override
+ public void onStart(FileAlterationObserver observer) {
+ if (Files.exists(Paths.get(path, lockFileName))) {
+ latch.countDown();
+ }
+ }
+
+ @Override
+ public void onFileCreate(File file) {
+ System.out.println("File created: " + file.getName());
+ latch.countDown();
+ }
+ });
+ monitor.addObserver(observer);
+
+ try {
+ monitor.start();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ boolean success = latch.await(10, TimeUnit.SECONDS);
+ try {
+ monitor.stop();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ if (!success) {
+ throw new TimeoutException("Timed out waiting for lock file creation: " + lockFileName);
+ }
+ // TODO This is a workaround for an edge condition that shows up with testing, where the lock is not reflected in
+ // the file system immediately. It is unlikely to appear in production environments. Should it occur, it will
+ // result in a lock file being erroneously reported as not having an owning process, and will cause a package to
+ // fail to be loaded from that cache until the lock is cleaned up by cache initialization.
+ Thread.sleep(100);
+
+ }
+
+
+}
diff --git a/org.hl7.fhir.validation.cli/pom.xml b/org.hl7.fhir.validation.cli/pom.xml
index de8286041..d802a4672 100644
--- a/org.hl7.fhir.validation.cli/pom.xml
+++ b/org.hl7.fhir.validation.cli/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
org.hl7.fhir.core
- 6.3.27-SNAPSHOT
+ 6.3.30-SNAPSHOT
../pom.xml
diff --git a/org.hl7.fhir.validation/pom.xml b/org.hl7.fhir.validation/pom.xml
index 19fe4ae82..92de2268c 100644
--- a/org.hl7.fhir.validation/pom.xml
+++ b/org.hl7.fhir.validation/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
org.hl7.fhir.core
- 6.3.27-SNAPSHOT
+ 6.3.30-SNAPSHOT
../pom.xml
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 cee1ebf8f..13b4304ca 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
@@ -1192,6 +1192,34 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi
}
+ protected int countFragmentMatches(Element element, String fragment, NodeStack stack) {
+ int count = countFragmentMatches(element, fragment);
+ if (count == 0 && element.isResource() && element.hasParentForValidator()) {
+ Element bnd = getElementBundle(element);
+ if (bnd != null) {
+ // in this case, we look into the parent - if there is one - and if it's a bundle, we look at the entries (but not in them)
+ for (Element be : bnd.getChildrenByName("entry")) {
+ String id = be.getIdBase();
+ if (fragment.equals(id)) {
+ count++;
+ }
+ }
+ }
+ }
+ return count;
+ }
+
+ private Element getElementBundle(Element element) {
+ Element p = element.getParentForValidator();
+ if (p != null) {
+ Element b = p.getParentForValidator();
+ if (b != null && b.fhirType().equals("Bundle")) {
+ return b;
+ }
+ }
+ return null;
+ }
+
protected int countFragmentMatches(Element element, String fragment) {
int count = 0;
if (fragment.equals(element.getIdBase())) {
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 418526071..a38b14fbb 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
@@ -130,7 +130,7 @@ public class CliContext {
private boolean showTimes = false;
@JsonProperty("locale")
- private String locale = Locale.ENGLISH.getDisplayLanguage();
+ private String locale = Locale.ENGLISH.toLanguageTag();
@JsonProperty("locations")
private Map locations = new HashMap();
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 82abdff63..a764d18d8 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
@@ -529,14 +529,18 @@ public class ValidationService {
}
@Nonnull
- protected ValidationEngine buildValidationEngine( CliContext cliContext, String definitions, TimeTracker timeTracker) throws IOException, URISyntaxException {
+ protected ValidationEngine buildValidationEngine(CliContext cliContext, String definitions, TimeTracker timeTracker) throws IOException, URISyntaxException {
System.out.print(" Load FHIR v" + cliContext.getSv() + " from " + definitions);
ValidationEngine validationEngine = getValidationEngineBuilder().withTHO(false).withVersion(cliContext.getSv()).withTimeTracker(timeTracker).withUserAgent(Common.getValidatorUserAgent()).fromSource(definitions);
System.out.println(" - " + validationEngine.getContext().countAllCaches() + " resources (" + timeTracker.milestone() + ")");
loadIgsAndExtensions(validationEngine, cliContext, timeTracker);
- if (validationEngine.getContext().getTxCache() == null) {
+ if (cliContext.getTxCache() != null) {
+ TerminologyCache cache = new TerminologyCache(new Object(), cliContext.getTxCache());
+ validationEngine.getContext().initTxCache(cache);
+ }
+ if (validationEngine.getContext().getTxCache() == null || validationEngine.getContext().getTxCache().getFolder() == null) {
System.out.println(" No Terminology Cache");
} else {
System.out.println(" Terminology Cache at "+validationEngine.getContext().getTxCache().getFolder());
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 5c191c7c9..9ea21787d 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
@@ -217,6 +217,7 @@ import org.hl7.fhir.validation.instance.type.ValueSetValidator;
import org.hl7.fhir.validation.instance.utils.*;
import org.w3c.dom.Document;
+
/**
* Thinking of using this in a java program? Don't!
* You should use one of the wrappers instead. Either in HAPI, or use ValidationEngine
@@ -1356,19 +1357,20 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
BindingStrength strength = binding.getStrength();
Extension maxVS = binding.getExtensionByUrl(ToolingExtensions.EXT_MAX_VALUESET);
- checkDisp = validateBindingCodeableConcept(errors, path, element, profile, stack, bh, checkDisp, checked, cc, vsRef, valueset, strength, maxVS, true);
+ checkDisp = validateBindingCodeableConcept(errors, path, element, profile, stack, bh, checkDisp, checked, cc, vsRef, valueset, strength, maxVS, true, null);
// } else if (binding.hasValueSet()) {
// hint(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_BINDING_CANTCHECK);
} else if (!noBindingMsgSuppressed) {
hint(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_BINDING_NOSOURCE, path);
}
for (ElementDefinitionBindingAdditionalComponent ab : binding.getAdditional()) {
- if (isTestableBinding(ab) && isInScope(ab)) {
+ StringBuilder b = new StringBuilder();
+ if (isTestableBinding(ab) && isInScope(ab, profile, getResource(stack), b)) {
String vsRef = ab.getValueSet();
ValueSet valueset = resolveBindingReference(profile, vsRef, profile.getUrl(), profile);
BindingStrength strength = convertPurposeToStrength(ab.getPurpose());
- checkDisp = validateBindingCodeableConcept(errors, path, element, profile, stack, bh, checkDisp, checked, cc, vsRef, valueset, strength, null, false) && checkDisp;
+ checkDisp = validateBindingCodeableConcept(errors, path, element, profile, stack, bh, checkDisp, checked, cc, vsRef, valueset, strength, null, false, b.toString()) && checkDisp;
}
}
} catch (CheckCodeOnServerException e) {
@@ -1394,25 +1396,186 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
return checkDisp;
}
- private boolean isInScope(ElementDefinitionBindingAdditionalComponent ab) {
+ private boolean isInScope(ElementDefinitionBindingAdditionalComponent ab, StructureDefinition profile, Element resource, StringBuilder b) {
+ if (ab.getUsage().isEmpty()) {
+ return true;
+ }
+ boolean ok = true;
for (UsageContext usage : ab.getUsage()) {
- if (isInScope(usage)) {
+ if (!isInScope(usage, profile, resource, b)) {
+ ok = false;
+ }
+ }
+ return ok;
+ }
+
+ private boolean isInScope(UsageContext usage, StructureDefinition profile, Element resource, StringBuilder b) {
+ if (isKnownUsage(usage)) {
+ return true;
+ }
+ if (usage.getCode().hasSystem() && (usage.getCode().getSystem().equals(profile.getUrl()) || usage.getCode().getSystem().equals(profile.getVersionedUrl()))) {
+ // if it's not a defined usage from external sources, it might match something in the data content
+ List items = findDataValue(resource, usage.getCode().getCode());
+ if (matchesUsage(items, usage.getValue())) {
+ b.append(context.formatMessage(I18nConstants.BINDING_ADDITIONAL_USAGE, displayCoding(usage.getCode()), display(usage.getValue())));
return true;
}
}
- return ab.getUsage().isEmpty();
+ return false;
}
- private boolean isInScope(UsageContext usage) {
- if (isKnownUsage(usage)) {
+ private String displayCoding(Coding value) {
+ return value.getCode();
+ }
+
+ private String displayCodeableConcept(CodeableConcept value) {
+ for (Coding c : value.getCoding()) {
+ String s = displayCoding(c);
+ if (s != null) {
+ return s;
+ }
+ }
+ return value.getText();
+ }
+
+ private String display(DataType value) {
+ switch (value.fhirType()) {
+ case "Coding" : return displayCoding((Coding) value);
+ case "CodeableConcept" : return displayCodeableConcept((CodeableConcept) value);
+ }
+ return value.fhirType();
+ }
+
+ private boolean matchesUsage(List items, DataType value) {
+ for (Element item : items) {
+ if (matchesUsage(item, value)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+
+ private String display(List items) {
+ CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder();
+ for (Element item : items) {
+ display(b, item);
+ }
+ return b.toString();
+ }
+
+ private void display(CommaSeparatedStringBuilder b, Element item) {
+ if (item.isPrimitive()) {
+ b.append(item.primitiveValue());
+ } else if (item.fhirType().equals("CodeableConcept")) {
+ for (Element c : item.getChildren("coding")) {
+ b.append(c.getNamedChildValue("code"));
+ }
+ } else {
+ b.append(item.toString());
+ }
+
+ }
+
+ private boolean matchesUsage(Element item, DataType value) {
+ switch (value.fhirType()) {
+ case "CodeableConcept": return matchesUsageCodeableConcept(item, (CodeableConcept) value);
+ case "Quantity": return false;
+ case "Range": return false;
+ case "Reference": return false;
+ default: return false;
+ }
+ }
+
+ private boolean matchesUsageCodeableConcept(Element item, CodeableConcept value) {
+ switch (item.fhirType()) {
+ case "CodeableConcept": return matchesUsageCodeableConceptCodeableConcept(item, value);
+ case "Coding": return matchesUsageCodeableConceptCoding(item, value);
+ default: return false;
+ }
+ }
+
+ private boolean matchesUsageCodeableConceptCoding(Element item, CodeableConcept value) {
+ String system = item.getNamedChildValue("system");
+ String version = item.getNamedChildValue("version");
+ String code = item.getNamedChildValue("code");
+ for (Coding c : value.getCoding()) {
+ if (system == null || !system.equals(c.getSystem())) {
+ return false;
+ }
+ if (code == null || !code.equals(c.getCode())) {
+ return false;
+ }
+ if (c.hasVersion()) {
+ if (version == null || !version.equals(c.getVersion())) {
+ return false;
+ }
+ }
return true;
}
return false;
}
+ private boolean matchesUsageCodeableConceptCodeableConcept(Element item, CodeableConcept value) {
+ for (Element code : item.getChildren("coding")) {
+ if (matchesUsageCodeableConceptCoding(code, value)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private List findDataValue(Element resource, String code) {
+ List items = new ArrayList();
+ if (resource != null) {
+ findDataValues(items, resource, code);
+ }
+ return items;
+ }
+
+ private void findDataValues(List