From 4f61f6f29e88b030069e3453db739c68da0d526a Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Thu, 14 Nov 2024 22:50:20 +1030 Subject: [PATCH 01/10] refactor UserData names to use constants --- .../convertors/SpecDifferenceEvaluator.java | 25 ++-- .../loaders/loaderR5/BaseLoaderR5.java | 7 +- .../fhir/r5/comparison/ComparisonSession.java | 7 +- .../StructureDefinitionComparer.java | 11 +- .../VersionComparisonAnnotation.java | 22 ++- .../conformance/profile/MappingAssistant.java | 7 +- .../profile/ProfilePathProcessor.java | 17 +-- .../conformance/profile/ProfileUtilities.java | 111 +++++++-------- .../fhir/r5/context/BaseWorkerContext.java | 13 +- .../hl7/fhir/r5/context/ContextUtilities.java | 7 +- .../fhir/r5/context/SimpleWorkerContext.java | 3 +- .../org/hl7/fhir/r5/elementmodel/Element.java | 7 +- .../fhir/r5/elementmodel/LanguageUtils.java | 28 ++-- .../hl7/fhir/r5/elementmodel/XmlParser.java | 3 +- .../hl7/fhir/r5/model/CanonicalResource.java | 5 +- .../r5/profilemodel/gen/PECodeGenerator.java | 15 +- .../renderers/AdditionalBindingsRenderer.java | 7 +- .../fhir/r5/renderers/CodeSystemRenderer.java | 8 +- .../hl7/fhir/r5/renderers/DataRenderer.java | 7 +- .../r5/renderers/ObligationsRenderer.java | 3 +- .../org/hl7/fhir/r5/renderers/Renderer.java | 11 +- .../StructureDefinitionRenderer.java | 75 +++++----- .../r5/renderers/TerminologyRenderer.java | 5 +- .../fhir/r5/renderers/ValueSetRenderer.java | 9 +- .../r5/terminologies/CodeSystemUtilities.java | 13 +- .../r5/terminologies/ValueSetUtilities.java | 17 +-- .../client/TerminologyClientManager.java | 5 +- .../expansion/ValueSetExpander.java | 9 +- .../utilities/ValueSetProcessBase.java | 5 +- .../validation/ValueSetValidator.java | 25 ++-- .../r5/utils/OperationOutcomeUtilities.java | 6 +- .../hl7/fhir/r5/utils/PackageHackerR5.java | 6 +- .../fhir/r5/utils/QuestionnaireBuilder.java | 18 +-- .../org/hl7/fhir/r5/utils/UserDataNames.java | 133 ++++++++++++++++++ .../org/hl7/fhir/r5/utils/sql/Runner.java | 29 ++-- .../org/hl7/fhir/r5/utils/sql/Validator.java | 27 ++-- .../structuremap/StructureMapUtilities.java | 9 +- .../hl7/fhir/validation/BaseValidator.java | 37 ++--- .../cli/renderers/DefaultRenderer.java | 3 +- .../type/StructureDefinitionValidator.java | 3 +- .../instance/type/StructureMapValidator.java | 23 +-- 41 files changed, 470 insertions(+), 311 deletions(-) create mode 100644 org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/UserDataNames.java diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/SpecDifferenceEvaluator.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/SpecDifferenceEvaluator.java index 51816b171..6fb89eaaf 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/SpecDifferenceEvaluator.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/SpecDifferenceEvaluator.java @@ -37,6 +37,7 @@ import org.hl7.fhir.r5.model.UriType; import org.hl7.fhir.r5.model.ValueSet; import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent; import org.hl7.fhir.r5.utils.ToolingExtensions; +import org.hl7.fhir.r5.utils.UserDataNames; import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; import org.hl7.fhir.utilities.IniFile; import org.hl7.fhir.utilities.Utilities; @@ -522,8 +523,8 @@ public class SpecDifferenceEvaluator { for (ElementDefinition ed : rev.getDifferential().getElement()) { ElementDefinition oed = getMatchingElement(rev.getName(), orig.getDifferential().getElement(), ed); if (oed != null) { - ed.setUserData("match", oed); - oed.setUserData("match", ed); + ed.setUserData(UserDataNames.comparison_match, oed); + oed.setUserData(UserDataNames.comparison_match, ed); } } @@ -556,9 +557,9 @@ public class SpecDifferenceEvaluator { right.ul().li().addText("No Changes"); for (ElementDefinition ed : rev.getDifferential().getElement()) - ed.clearUserData("match"); + ed.clearUserData(UserDataNames.comparison_match); for (ElementDefinition ed : orig.getDifferential().getElement()) - ed.clearUserData("match"); + ed.clearUserData(UserDataNames.comparison_match); } @@ -1078,8 +1079,8 @@ public class SpecDifferenceEvaluator { for (ElementDefinition ed : rev.getDifferential().getElement()) { ElementDefinition oed = getMatchingElement(rev.getName(), orig.getDifferential().getElement(), ed); if (oed != null) { - ed.setUserData("match", oed); - oed.setUserData("match", ed); + ed.setUserData(UserDataNames.comparison_match, oed); + oed.setUserData(UserDataNames.comparison_match, ed); } } @@ -1121,9 +1122,9 @@ public class SpecDifferenceEvaluator { type.addProperty("status", "no-change"); for (ElementDefinition ed : rev.getDifferential().getElement()) - ed.clearUserData("match"); + ed.clearUserData(UserDataNames.comparison_match); for (ElementDefinition ed : orig.getDifferential().getElement()) - ed.clearUserData("match"); + ed.clearUserData(UserDataNames.comparison_match); } @@ -1137,8 +1138,8 @@ public class SpecDifferenceEvaluator { for (ElementDefinition ed : rev.getDifferential().getElement()) { ElementDefinition oed = getMatchingElement(rev.getName(), orig.getDifferential().getElement(), ed); if (oed != null) { - ed.setUserData("match", oed); - oed.setUserData("match", ed); + ed.setUserData(UserDataNames.comparison_match, oed); + oed.setUserData(UserDataNames.comparison_match, ed); } } @@ -1179,9 +1180,9 @@ public class SpecDifferenceEvaluator { type.setAttribute("status", "no-change"); for (ElementDefinition ed : rev.getDifferential().getElement()) - ed.clearUserData("match"); + ed.clearUserData(UserDataNames.comparison_match); for (ElementDefinition ed : orig.getDifferential().getElement()) - ed.clearUserData("match"); + ed.clearUserData(UserDataNames.comparison_match); } diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/loaderR5/BaseLoaderR5.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/loaderR5/BaseLoaderR5.java index 7ad7c0628..aec2f97c7 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/loaderR5/BaseLoaderR5.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/loaderR5/BaseLoaderR5.java @@ -19,6 +19,7 @@ import org.hl7.fhir.r5.model.UriType; import org.hl7.fhir.r5.model.ValueSet; import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent; import org.hl7.fhir.r5.utils.ToolingExtensions; +import org.hl7.fhir.r5.utils.UserDataNames; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.VersionUtilities; import org.hl7.fhir.utilities.npm.NpmPackage; @@ -54,9 +55,9 @@ public abstract class BaseLoaderR5 implements IContextResourceLoader { public void setPath(Resource r) { String path = lkp.getResourcePath(r); if (lkp.getWebRoot() != null) { - r.setUserData("webroot", lkp.getWebRoot()); + r.setUserData(UserDataNames.render_webroot, lkp.getWebRoot()); } else { - r.setUserData("webroot", ""); + r.setUserData(UserDataNames.render_webroot, ""); } if (path != null) { r.setWebPath(path); @@ -116,7 +117,7 @@ public abstract class BaseLoaderR5 implements IContextResourceLoader { // and we only patch URLs to support version transforms // so we just patch sd/od -> vs -> cs protected void doPatchUrls(Resource resource) { - resource.setUserData("old.load.mode", true); + resource.setUserData(UserDataNames.loader_urls_patched, true); if (resource instanceof CanonicalResource) { CanonicalResource cr = (CanonicalResource) resource; cr.setUrl(patchUrl(cr.getUrl(), cr.fhirType())); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/ComparisonSession.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/ComparisonSession.java index 52f4f5db1..7eaeb5edd 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/ComparisonSession.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/ComparisonSession.java @@ -26,6 +26,7 @@ import org.hl7.fhir.r5.model.Resource; import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.r5.model.ValueSet; import org.hl7.fhir.r5.renderers.utils.RenderingContext; +import org.hl7.fhir.r5.utils.UserDataNames; import org.hl7.fhir.utilities.i18n.RenderingI18nContext; public class ComparisonSession { @@ -191,11 +192,11 @@ public class ComparisonSession { if (b == null) { return null; } - if (b.hasUserData(VersionComparisonAnnotation.USER_DATA_NAME)) { - return (VersionComparisonAnnotation) b.getUserData(VersionComparisonAnnotation.USER_DATA_NAME); + if (b.hasUserData(UserDataNames.COMP_VERSION_ANNOTATION)) { + return (VersionComparisonAnnotation) b.getUserData(UserDataNames.COMP_VERSION_ANNOTATION); } else { VersionComparisonAnnotation vca = new VersionComparisonAnnotation(AnotationType.NoChange); - b.setUserData(VersionComparisonAnnotation.USER_DATA_NAME, vca); + b.setUserData(UserDataNames.COMP_VERSION_ANNOTATION, vca); return vca; } } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/StructureDefinitionComparer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/StructureDefinitionComparer.java index b935e8eef..fa6f10230 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/StructureDefinitionComparer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/StructureDefinitionComparer.java @@ -41,6 +41,7 @@ import org.hl7.fhir.r5.renderers.utils.RenderingContext; import org.hl7.fhir.r5.renderers.utils.RenderingContext.GenerationRules; import org.hl7.fhir.r5.renderers.utils.RenderingContext.ResourceRendererMode; import org.hl7.fhir.r5.utils.DefinitionNavigator; +import org.hl7.fhir.r5.utils.UserDataNames; import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.validation.ValidationMessage; @@ -870,12 +871,12 @@ public class StructureDefinitionComparer extends CanonicalResourceComparer imple ex.setProfile(null); } else { // both have profiles. Is one derived from the other? - StructureDefinition sdex = ((IWorkerContext) ex.getUserData("ctxt")).fetchResource(StructureDefinition.class, ex.getProfile().get(0).getValue(), nwSource); + StructureDefinition sdex = ((IWorkerContext) ex.getUserData(UserDataNames.COMP_CONTEXT)).fetchResource(StructureDefinition.class, ex.getProfile().get(0).getValue(), nwSource); StructureDefinition sdnw = ctxt.fetchResource(StructureDefinition.class, nw.getProfile().get(0).getValue(), nwSource); if (sdex != null && sdnw != null) { if (sdex.getUrl().equals(sdnw.getUrl())) { pfound = true; - } else if (derivesFrom(sdex, sdnw, ((IWorkerContext) ex.getUserData("ctxt")))) { + } else if (derivesFrom(sdex, sdnw, ((IWorkerContext) ex.getUserData(UserDataNames.COMP_CONTEXT)))) { ex.setProfile(nw.getProfile()); pfound = true; } else if (derivesFrom(sdnw, sdex, ctxt)) { @@ -898,12 +899,12 @@ public class StructureDefinitionComparer extends CanonicalResourceComparer imple ex.setTargetProfile(null); } else { // both have profiles. Is one derived from the other? - StructureDefinition sdex = ((IWorkerContext) ex.getUserData("ctxt")).fetchResource(StructureDefinition.class, ex.getTargetProfile().get(0).getValue(), nwSource); + StructureDefinition sdex = ((IWorkerContext) ex.getUserData(UserDataNames.COMP_CONTEXT)).fetchResource(StructureDefinition.class, ex.getTargetProfile().get(0).getValue(), nwSource); StructureDefinition sdnw = ctxt.fetchResource(StructureDefinition.class, nw.getTargetProfile().get(0).getValue(), nwSource); if (sdex != null && sdnw != null) { if (matches(sdex, sdnw)) { tfound = true; - } else if (derivesFrom(sdex, sdnw, ((IWorkerContext) ex.getUserData("ctxt")))) { + } else if (derivesFrom(sdex, sdnw, ((IWorkerContext) ex.getUserData(UserDataNames.COMP_CONTEXT)))) { ex.setTargetProfile(nw.getTargetProfile()); tfound = true; } else if (derivesFrom(sdnw, sdex, ctxt)) { @@ -925,7 +926,7 @@ public class StructureDefinitionComparer extends CanonicalResourceComparer imple } } if (!tfound || !pfound) { - nw.setUserData("ctxt", ctxt); + nw.setUserData(UserDataNames.COMP_CONTEXT, ctxt); results.add(nw); } } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/VersionComparisonAnnotation.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/VersionComparisonAnnotation.java index b57a64001..4dbee9fd5 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/VersionComparisonAnnotation.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/VersionComparisonAnnotation.java @@ -8,6 +8,7 @@ import java.util.Map; import org.hl7.fhir.r5.comparison.CanonicalResourceComparer.CanonicalResourceComparison; import org.hl7.fhir.r5.model.Base; import org.hl7.fhir.r5.model.CanonicalResource; +import org.hl7.fhir.r5.utils.UserDataNames; public class VersionComparisonAnnotation { @@ -15,7 +16,6 @@ public class VersionComparisonAnnotation { NoChange, Added, Changed, Deleted; } - public static final String USER_DATA_NAME = "version-annotation"; private AnotationType type; private String original; @@ -66,10 +66,6 @@ public class VersionComparisonAnnotation { this.comp = comp; } - public static String getUserDataName() { - return USER_DATA_NAME; - } - public AnotationType getType() { return type; } @@ -89,8 +85,8 @@ public class VersionComparisonAnnotation { public static boolean hasDeleted(Base base, String... names) { boolean result = false; - if (base.hasUserData(USER_DATA_NAME)) { - VersionComparisonAnnotation self = (VersionComparisonAnnotation) base.getUserData(USER_DATA_NAME); + if (base.hasUserData(UserDataNames.COMP_VERSION_ANNOTATION)) { + VersionComparisonAnnotation self = (VersionComparisonAnnotation) base.getUserData(UserDataNames.COMP_VERSION_ANNOTATION); for (String name : names) { if (self.deletedChildren != null && self.deletedChildren.containsKey(name)) { result = true; @@ -102,8 +98,8 @@ public class VersionComparisonAnnotation { public static List getDeleted(Base base, String... names) { List result = new ArrayList<>(); - if (base.hasUserData(USER_DATA_NAME)) { - VersionComparisonAnnotation self = (VersionComparisonAnnotation) base.getUserData(USER_DATA_NAME); + if (base.hasUserData(UserDataNames.COMP_VERSION_ANNOTATION)) { + VersionComparisonAnnotation self = (VersionComparisonAnnotation) base.getUserData(UserDataNames.COMP_VERSION_ANNOTATION); for (String name : names) { if (self.deletedChildren != null && self.deletedChildren.containsKey(name)) { result.addAll(self.deletedChildren.get(name)); @@ -115,8 +111,8 @@ public class VersionComparisonAnnotation { public static Base getDeletedItem(Base base, String name) { List result = new ArrayList<>(); - if (base.hasUserData(USER_DATA_NAME)) { - VersionComparisonAnnotation self = (VersionComparisonAnnotation) base.getUserData(USER_DATA_NAME); + if (base.hasUserData(UserDataNames.COMP_VERSION_ANNOTATION)) { + VersionComparisonAnnotation self = (VersionComparisonAnnotation) base.getUserData(UserDataNames.COMP_VERSION_ANNOTATION); if (self.deletedChildren != null && self.deletedChildren.containsKey(name)) { result.addAll(self.deletedChildren.get(name)); } @@ -128,8 +124,8 @@ public class VersionComparisonAnnotation { public static CanonicalResourceComparison artifactComparison(Base base) { - if (base.hasUserData(USER_DATA_NAME)) { - VersionComparisonAnnotation self = (VersionComparisonAnnotation) base.getUserData(USER_DATA_NAME); + if (base.hasUserData(UserDataNames.COMP_VERSION_ANNOTATION)) { + VersionComparisonAnnotation self = (VersionComparisonAnnotation) base.getUserData(UserDataNames.COMP_VERSION_ANNOTATION); return self.comp; } else { return null; diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/MappingAssistant.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/MappingAssistant.java index 42daed659..923726bf1 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/MappingAssistant.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/MappingAssistant.java @@ -14,6 +14,7 @@ import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionMappingComponent; import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionMappingComponent; import org.hl7.fhir.r5.utils.ToolingExtensions; +import org.hl7.fhir.r5.utils.UserDataNames; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.VersionUtilities; import org.hl7.fhir.utilities.i18n.I18nConstants; @@ -47,7 +48,7 @@ public class MappingAssistant { for (StructureDefinitionMappingComponent m : derived.getMapping()) { masterList.add(m); if (!isSuppressed(m)) { - m.setUserData("private-marked-as-derived", true); + m.setUserData(UserDataNames.mappings_inherited, true); } } @@ -127,7 +128,7 @@ public class MappingAssistant { derived.getMapping().clear(); for (StructureDefinitionMappingComponent t : masterList) { - if (usedList.contains(t) || t.hasUserData("private-marked-as-derived")) { + if (usedList.contains(t) || t.hasUserData(UserDataNames.mappings_inherited)) { derived.getMapping().add(t); } } @@ -163,7 +164,7 @@ public class MappingAssistant { for (ElementDefinitionMappingComponent d : destination) { if (compareMaps(name, s, d)) { found = true; - d.setUserData(ProfileUtilities.UD_DERIVATION_EQUALS, true); + d.setUserData(UserDataNames.SNAPSHOT_DERIVATION_EQUALS, true); break; } } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfilePathProcessor.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfilePathProcessor.java index a26d81569..648a4b864 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfilePathProcessor.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfilePathProcessor.java @@ -19,6 +19,7 @@ import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind; import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionSnapshotComponent; import org.hl7.fhir.r5.utils.ToolingExtensions; +import org.hl7.fhir.r5.utils.UserDataNames; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.VersionUtilities; import org.hl7.fhir.utilities.i18n.I18nConstants; @@ -201,7 +202,7 @@ public class ProfilePathProcessor { // int i = 0; // List list = getDifferential().getElement(); // for (ElementDefinition ed : list) { -// boolean assigned = ed.hasUserData("derived.pointer"); +// boolean assigned = ed.hasUserData(UserDataNames.UD_DERIVATION_POINTER); // if (i < cursors.diffCursor) { // if (!assigned) { // throw new Error("what?"); @@ -295,7 +296,7 @@ public class ProfilePathProcessor { if (!diffMatches.get(0).hasSlicing()) { outcome.setSlicing(profileUtilities.makeExtensionSlicing()); - outcome.setUserData("auto-added-slicing", true); + outcome.setUserData(UserDataNames.SNAPSHOT_auto_added_slicing, true); } else { outcome.setSlicing(diffMatches.get(0).getSlicing().copy()); for (int i = 1; i < diffMatches.size(); i++) { @@ -1041,9 +1042,9 @@ public class ProfilePathProcessor { profileUtilities.updateFromDefinition(outcome, diffMatches.get(0), getProfileName(), closed, getUrl(), getSourceStructureDefinition(), getDerived(), diffPath(diffMatches.get(0)), mapHelper); // if there's no slice, we don't want to update the unsliced description profileUtilities.removeStatusExtensions(outcome); } else if (!diffMatches.get(0).hasSliceName()) { - diffMatches.get(0).setUserData(profileUtilities.UD_GENERATED_IN_SNAPSHOT, outcome); // because of updateFromDefinition isn't called + diffMatches.get(0).setUserData(UserDataNames.SNAPSHOT_GENERATED_IN_SNAPSHOT, outcome); // because of updateFromDefinition isn't called } else { - outcome.setUserData("auto-added-slicing", true); + outcome.setUserData(UserDataNames.SNAPSHOT_auto_added_slicing, true); } debugCheck(outcome); @@ -1143,8 +1144,8 @@ public class ProfilePathProcessor { outcome.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), outcome.getPath(), getRedirector(), getContextPathSource())); if (!outcome.getPath().startsWith(cursors.resultPathBase)) throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ADDING_WRONG_PATH)); - outcome.setUserData(profileUtilities.UD_BASE_PATH, outcome.getPath()); - outcome.setUserData(profileUtilities.UD_BASE_MODEL, getSourceStructureDefinition().getUrl()); + outcome.setUserData(UserDataNames.SNAPSHOT_BASE_PATH, outcome.getPath()); + outcome.setUserData(UserDataNames.SNAPSHOT_BASE_MODEL, getSourceStructureDefinition().getUrl()); debugCheck(outcome); getResult().getElement().add(outcome); cursors.baseCursor++; @@ -1463,8 +1464,8 @@ public class ProfilePathProcessor { throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ADDING_WRONG_PATH_IN_PROFILE___VS_, getProfileName(), outcome.getPath(), cursors.resultPathBase)); debugCheck(outcome); getResult().getElement().add(outcome); // so we just copy it in - outcome.setUserData(profileUtilities.UD_BASE_MODEL, getSourceStructureDefinition().getUrl()); - outcome.setUserData(profileUtilities.UD_BASE_PATH, cursors.resultPathBase); + outcome.setUserData(UserDataNames.SNAPSHOT_BASE_MODEL, getSourceStructureDefinition().getUrl()); + outcome.setUserData(UserDataNames.SNAPSHOT_BASE_PATH, cursors.resultPathBase); cursors.baseCursor++; } } 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 4aa657d35..0e2474cb0 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 @@ -100,6 +100,7 @@ import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent; import org.hl7.fhir.r5.terminologies.expansion.ValueSetExpansionOutcome; import org.hl7.fhir.r5.terminologies.utilities.ValidationResult; import org.hl7.fhir.r5.utils.ToolingExtensions; +import org.hl7.fhir.r5.utils.UserDataNames; import org.hl7.fhir.r5.utils.XVerExtensionManager; import org.hl7.fhir.r5.utils.XVerExtensionManager.XVerExtensionStatus; import org.hl7.fhir.r5.utils.formats.CSVWriter; @@ -412,12 +413,6 @@ public class ProfileUtilities { } } - public static final String UD_BASE_MODEL = "base.model"; - public static final String UD_BASE_PATH = "base.path"; - public static final String UD_DERIVATION_EQUALS = "derivation.equals"; - public static final String UD_DERIVATION_POINTER = "derived.pointer"; - public static final String UD_IS_DERIVED = "derived.fact"; - public static final String UD_GENERATED_IN_SNAPSHOT = "profileutilities.snapshot.processed"; private static final boolean COPY_BINDING_EXTENSIONS = false; private static final boolean DONT_DO_THIS = false; @@ -727,7 +722,7 @@ public class ProfileUtilities { if (snapshotStack.contains(derived.getUrl())) { throw new DefinitionException(context.formatMessage(I18nConstants.CIRCULAR_SNAPSHOT_REFERENCES_DETECTED_CANNOT_GENERATE_SNAPSHOT_STACK__, snapshotStack.toString())); } - derived.setUserData("profileutils.snapshot.generating", true); + derived.setUserData(UserDataNames.SNAPSHOT_GENERATING, true); snapshotStack.add(derived.getUrl()); try { @@ -755,7 +750,7 @@ public class ProfileUtilities { for (ElementDefinition e : derived.getDifferential().getElement()) - e.clearUserData(UD_GENERATED_IN_SNAPSHOT); + e.clearUserData(UserDataNames.SNAPSHOT_GENERATED_IN_SNAPSHOT); // we actually delegate the work to a subroutine so we can re-enter it with a different cursors StructureDefinitionDifferentialComponent diff = cloneDiff(derived.getDifferential()); // we make a copy here because we're sometimes going to hack the differential while processing it. Have to migrate user data back afterwards @@ -778,13 +773,13 @@ public class ProfileUtilities { if (derived.getDerivation() == TypeDerivationRule.SPECIALIZATION) { int i = 0; for (ElementDefinition e : diff.getElement()) { - if (!e.hasUserData(UD_GENERATED_IN_SNAPSHOT) && e.getPath().contains(".")) { + if (!e.hasUserData(UserDataNames.SNAPSHOT_GENERATED_IN_SNAPSHOT) && e.getPath().contains(".")) { ElementDefinition existing = getElementInCurrentContext(e.getPath(), derived.getSnapshot().getElement()); if (existing != null) { updateFromDefinition(existing, e, profileName, false, url, base, derived, "StructureDefinition.differential.element["+i+"]", mappingDetails); } else { ElementDefinition outcome = updateURLs(url, webUrl, e.copy(), true); - e.setUserData(UD_GENERATED_IN_SNAPSHOT, outcome); + e.setUserData(UserDataNames.SNAPSHOT_GENERATED_IN_SNAPSHOT, outcome); derived.getSnapshot().addElement(outcome); if (walksInto(diff.getElement(), e)) { if (e.getType().size() > 1) { @@ -813,22 +808,22 @@ public class ProfileUtilities { System.out.println(" "+ed.getId()+" : "+typeSummaryWithProfile(ed)+"["+ed.getMin()+".."+ed.getMax()+"]"+sliceSummary(ed)+" "+constraintSummary(ed)); System.out.println("diff: "); for (ElementDefinition ed : diff.getElement()) - System.out.println(" "+ed.getId()+" : "+typeSummaryWithProfile(ed)+"["+ed.getMin()+".."+ed.getMax()+"]"+sliceSummary(ed)+" "+constraintSummary(ed)+" [gen = "+(ed.hasUserData(UD_GENERATED_IN_SNAPSHOT) ? ed.getUserData(UD_GENERATED_IN_SNAPSHOT) : "--")+"]"); + System.out.println(" "+ed.getId()+" : "+typeSummaryWithProfile(ed)+"["+ed.getMin()+".."+ed.getMax()+"]"+sliceSummary(ed)+" "+constraintSummary(ed)+" [gen = "+(ed.hasUserData(UserDataNames.SNAPSHOT_GENERATED_IN_SNAPSHOT) ? ed.getUserData(UserDataNames.SNAPSHOT_GENERATED_IN_SNAPSHOT) : "--")+"]"); } CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(); //Check that all differential elements have a corresponding snapshot element int ce = 0; int i = 0; for (ElementDefinition e : diff.getElement()) { - if (!e.hasUserData("diff-source")) + if (!e.hasUserData(UserDataNames.SNAPSHOT_diff_source)) throw new Error(context.formatMessage(I18nConstants.UNXPECTED_INTERNAL_CONDITION__NO_SOURCE_ON_DIFF_ELEMENT)); else { - if (e.hasUserData(UD_DERIVATION_EQUALS)) - ((Base) e.getUserData("diff-source")).setUserData(UD_DERIVATION_EQUALS, e.getUserData(UD_DERIVATION_EQUALS)); - if (e.hasUserData(UD_DERIVATION_POINTER)) - ((Base) e.getUserData("diff-source")).setUserData(UD_DERIVATION_POINTER, e.getUserData(UD_DERIVATION_POINTER)); + if (e.hasUserData(UserDataNames.SNAPSHOT_DERIVATION_EQUALS)) + ((Base) e.getUserData(UserDataNames.SNAPSHOT_diff_source)).setUserData(UserDataNames.SNAPSHOT_DERIVATION_EQUALS, e.getUserData(UserDataNames.SNAPSHOT_DERIVATION_EQUALS)); + if (e.hasUserData(UserDataNames.SNAPSHOT_DERIVATION_POINTER)) + ((Base) e.getUserData(UserDataNames.SNAPSHOT_diff_source)).setUserData(UserDataNames.SNAPSHOT_DERIVATION_POINTER, e.getUserData(UserDataNames.SNAPSHOT_DERIVATION_POINTER)); } - if (!e.hasUserData(UD_GENERATED_IN_SNAPSHOT)) { + if (!e.hasUserData(UserDataNames.SNAPSHOT_GENERATED_IN_SNAPSHOT)) { b.append(e.hasId() ? "id: "+e.getId() : "path: "+e.getPath()); ce++; if (e.hasId()) { @@ -902,7 +897,7 @@ public class ProfileUtilities { int count = slice.checkMin(); boolean repeats = !"1".equals(slice.getFocus().getBase().getMax()); // type slicing if repeats = 1 if (count > -1 && repeats) { - if (slice.getFocus().hasUserData("auto-added-slicing")) { + if (slice.getFocus().hasUserData(UserDataNames.SNAPSHOT_auto_added_slicing)) { slice.getFocus().setMin(count); } else { String msg = "The slice definition for "+slice.getFocus().getId()+" has a minimum of "+slice.getFocus().getMin()+" but the slices add up to a minimum of "+count; @@ -985,15 +980,15 @@ public class ProfileUtilities { } catch (Exception e) { // if we had an exception generating the snapshot, make sure we don't leave any half generated snapshot behind derived.setSnapshot(null); - derived.clearUserData("profileutils.snapshot.generating"); + derived.clearUserData(UserDataNames.SNAPSHOT_GENERATING); throw e; } } finally { - derived.clearUserData("profileutils.snapshot.generating"); + derived.clearUserData(UserDataNames.SNAPSHOT_GENERATING); snapshotStack.remove(derived.getUrl()); } - derived.setUserData("profileutils.snapshot.generated", true); // used by the publisher - derived.setUserData("profileutils.snapshot.generated.messages", messages); // used by the publisher + derived.setUserData(UserDataNames.SNAPSHOT_GENERATED, true); // used by the publisher + derived.setUserData(UserDataNames.SNAPSHOT_GENERATED_MESSAGES, messages); // used by the publisher } @@ -1304,7 +1299,7 @@ public class ProfileUtilities { for (ElementDefinition sed : source.getElement()) { ElementDefinition ted = sed.copy(); diff.getElement().add(ted); - ted.setUserData("diff-source", sed); + ted.setUserData(UserDataNames.SNAPSHOT_diff_source, sed); } return diff; } @@ -1504,12 +1499,12 @@ public class ProfileUtilities { } protected boolean isGenerating(StructureDefinition sd) { - return sd.hasUserData("profileutils.snapshot.generating"); + return sd.hasUserData(UserDataNames.SNAPSHOT_GENERATING); } protected void checkNotGenerating(StructureDefinition sd, String role) { - if (sd.hasUserData("profileutils.snapshot.generating")) { + if (sd.hasUserData(UserDataNames.SNAPSHOT_GENERATING)) { throw new FHIRException(context.formatMessage(I18nConstants.ATTEMPT_TO_USE_A_SNAPSHOT_ON_PROFILE__AS__BEFORE_IT_IS_GENERATED, sd.getUrl(), role)); } } @@ -1792,7 +1787,7 @@ public class ProfileUtilities { protected void markDerived(ElementDefinition outcome) { for (ElementDefinitionConstraintComponent inv : outcome.getConstraint()) - inv.setUserData(UD_IS_DERIVED, true); + inv.setUserData(UserDataNames.SNAPSHOT_IS_DERIVED, true); } @@ -1823,8 +1818,8 @@ public class ProfileUtilities { protected void updateFromBase(ElementDefinition derived, ElementDefinition base, String baseProfileUrl) { - derived.setUserData(UD_BASE_MODEL, baseProfileUrl); - derived.setUserData(UD_BASE_PATH, base.getPath()); + derived.setUserData(UserDataNames.SNAPSHOT_BASE_MODEL, baseProfileUrl); + derived.setUserData(UserDataNames.SNAPSHOT_BASE_PATH, base.getPath()); if (base.hasBase()) { if (!derived.hasBase()) derived.setBase(new ElementDefinitionBaseComponent()); @@ -2395,12 +2390,12 @@ public class ProfileUtilities { protected void updateFromDefinition(ElementDefinition dest, ElementDefinition source, String pn, boolean trimDifferential, String purl, StructureDefinition srcSD, StructureDefinition derivedSrc, String path, MappingAssistant mappings) throws DefinitionException, FHIRException { - source.setUserData(UD_GENERATED_IN_SNAPSHOT, dest); + source.setUserData(UserDataNames.SNAPSHOT_GENERATED_IN_SNAPSHOT, dest); // we start with a clone of the base profile ('dest') and we copy from the profile ('source') // over the top for anything the source has ElementDefinition base = dest; ElementDefinition derived = source; - derived.setUserData(UD_DERIVATION_POINTER, base); + derived.setUserData(UserDataNames.SNAPSHOT_DERIVATION_POINTER, base); boolean isExtension = checkExtensionDoco(base); List obligationProfileElements = new ArrayList<>(); for (StructureDefinition sd : obligationProfiles) { @@ -2461,7 +2456,7 @@ public class ProfileUtilities { throw new DefinitionException(context.formatMessage(I18nConstants.SNAPSHOT_IS_EMPTY, profile.getVersionedUrl())); } ElementDefinition e = profile.getSnapshot().getElement().get(0); - String webroot = profile.getUserString("webroot"); + String webroot = profile.getUserString(UserDataNames.render_webroot); if (e.hasDefinition()) { base.setDefinition(processRelativeUrls(e.getDefinition(), webroot, context.getSpecUrl(), context.getResourceNames(), masterSourceFileNames, localFileNames, true)); @@ -2506,7 +2501,7 @@ public class ProfileUtilities { else if (trimDifferential) derived.setShortElement(null); else if (derived.hasShortElement()) - derived.getShortElement().setUserData(UD_DERIVATION_EQUALS, true); + derived.getShortElement().setUserData(UserDataNames.SNAPSHOT_DERIVATION_EQUALS, true); } if (derived.hasDefinitionElement()) { @@ -2517,7 +2512,7 @@ public class ProfileUtilities { } else if (trimDifferential) derived.setDefinitionElement(null); else if (derived.hasDefinitionElement()) - derived.getDefinitionElement().setUserData(UD_DERIVATION_EQUALS, true); + derived.getDefinitionElement().setUserData(UserDataNames.SNAPSHOT_DERIVATION_EQUALS, true); } if (derived.hasCommentElement()) { @@ -2528,7 +2523,7 @@ public class ProfileUtilities { else if (trimDifferential) base.setCommentElement(derived.getCommentElement().copy()); else if (derived.hasCommentElement()) - derived.getCommentElement().setUserData(UD_DERIVATION_EQUALS, true); + derived.getCommentElement().setUserData(UserDataNames.SNAPSHOT_DERIVATION_EQUALS, true); } if (derived.hasLabelElement()) { @@ -2539,7 +2534,7 @@ public class ProfileUtilities { else if (trimDifferential) base.setLabelElement(derived.getLabelElement().copy()); else if (derived.hasLabelElement()) - derived.getLabelElement().setUserData(UD_DERIVATION_EQUALS, true); + derived.getLabelElement().setUserData(UserDataNames.SNAPSHOT_DERIVATION_EQUALS, true); } if (derived.hasRequirementsElement()) { @@ -2550,7 +2545,7 @@ public class ProfileUtilities { else if (trimDifferential) base.setRequirementsElement(derived.getRequirementsElement().copy()); else if (derived.hasRequirementsElement()) - derived.getRequirementsElement().setUserData(UD_DERIVATION_EQUALS, true); + derived.getRequirementsElement().setUserData(UserDataNames.SNAPSHOT_DERIVATION_EQUALS, true); } // sdf-9 if (derived.hasRequirements() && !base.getPath().contains(".")) @@ -2568,7 +2563,7 @@ public class ProfileUtilities { derived.getAlias().clear(); else for (StringType t : derived.getAlias()) - t.setUserData(UD_DERIVATION_EQUALS, true); + t.setUserData(UserDataNames.SNAPSHOT_DERIVATION_EQUALS, true); } if (derived.hasMinElement()) { @@ -2579,7 +2574,7 @@ public class ProfileUtilities { } else if (trimDifferential) derived.setMinElement(null); else - derived.getMinElement().setUserData(UD_DERIVATION_EQUALS, true); + derived.getMinElement().setUserData(UserDataNames.SNAPSHOT_DERIVATION_EQUALS, true); } if (derived.hasMaxElement()) { @@ -2590,7 +2585,7 @@ public class ProfileUtilities { } else if (trimDifferential) derived.setMaxElement(null); else - derived.getMaxElement().setUserData(UD_DERIVATION_EQUALS, true); + derived.getMaxElement().setUserData(UserDataNames.SNAPSHOT_DERIVATION_EQUALS, true); } if (derived.hasFixed()) { @@ -2599,7 +2594,7 @@ public class ProfileUtilities { } else if (trimDifferential) derived.setFixed(null); else - derived.getFixed().setUserData(UD_DERIVATION_EQUALS, true); + derived.getFixed().setUserData(UserDataNames.SNAPSHOT_DERIVATION_EQUALS, true); } if (derived.hasPattern()) { @@ -2609,7 +2604,7 @@ public class ProfileUtilities { if (trimDifferential) derived.setPattern(null); else - derived.getPattern().setUserData(UD_DERIVATION_EQUALS, true); + derived.getPattern().setUserData(UserDataNames.SNAPSHOT_DERIVATION_EQUALS, true); } List toDelB = new ArrayList<>(); @@ -2636,7 +2631,7 @@ public class ProfileUtilities { } else if (trimDifferential) { derived.getExample().remove(ex); } else { - ex.setUserData(UD_DERIVATION_EQUALS, true); + ex.setUserData(UserDataNames.SNAPSHOT_DERIVATION_EQUALS, true); } } } @@ -2649,7 +2644,7 @@ public class ProfileUtilities { else if (trimDifferential) derived.setMaxLengthElement(null); else - derived.getMaxLengthElement().setUserData(UD_DERIVATION_EQUALS, true); + derived.getMaxLengthElement().setUserData(UserDataNames.SNAPSHOT_DERIVATION_EQUALS, true); } if (derived.hasMaxValue()) { @@ -2658,7 +2653,7 @@ public class ProfileUtilities { else if (trimDifferential) derived.setMaxValue(null); else - derived.getMaxValue().setUserData(UD_DERIVATION_EQUALS, true); + derived.getMaxValue().setUserData(UserDataNames.SNAPSHOT_DERIVATION_EQUALS, true); } if (derived.hasMinValue()) { @@ -2667,7 +2662,7 @@ public class ProfileUtilities { else if (trimDifferential) derived.setMinValue(null); else - derived.getMinValue().setUserData(UD_DERIVATION_EQUALS, true); + derived.getMinValue().setUserData(UserDataNames.SNAPSHOT_DERIVATION_EQUALS, true); } // todo: what to do about conditions? @@ -2693,7 +2688,7 @@ public class ProfileUtilities { } else if (trimDifferential) derived.setMustSupportElement(null); else - derived.getMustSupportElement().setUserData(UD_DERIVATION_EQUALS, true); + derived.getMustSupportElement().setUserData(UserDataNames.SNAPSHOT_DERIVATION_EQUALS, true); } if (derived.hasMustHaveValueElement()) { @@ -2705,7 +2700,7 @@ public class ProfileUtilities { } else if (trimDifferential) derived.setMustHaveValueElement(null); else - derived.getMustHaveValueElement().setUserData(UD_DERIVATION_EQUALS, true); + derived.getMustHaveValueElement().setUserData(UserDataNames.SNAPSHOT_DERIVATION_EQUALS, true); } if (derived.hasValueAlternatives()) { if (!Base.compareDeep(derived.getValueAlternatives(), base.getValueAlternatives(), false)) @@ -2717,7 +2712,7 @@ public class ProfileUtilities { derived.getValueAlternatives().clear(); else for (CanonicalType t : derived.getValueAlternatives()) - t.setUserData(UD_DERIVATION_EQUALS, true); + t.setUserData(UserDataNames.SNAPSHOT_DERIVATION_EQUALS, true); } // profiles cannot change : isModifier, defaultValue, meaningWhenMissing @@ -2728,13 +2723,13 @@ public class ProfileUtilities { else if (trimDifferential) derived.setIsModifierElement(null); else if (derived.hasIsModifierElement()) - derived.getIsModifierElement().setUserData(UD_DERIVATION_EQUALS, true); + derived.getIsModifierElement().setUserData(UserDataNames.SNAPSHOT_DERIVATION_EQUALS, true); if (derived.hasIsModifierReasonElement() && !(base.hasIsModifierReasonElement() && Base.compareDeep(derived.getIsModifierReasonElement(), base.getIsModifierReasonElement(), false))) base.setIsModifierReasonElement(derived.getIsModifierReasonElement().copy()); else if (trimDifferential) derived.setIsModifierReasonElement(null); else if (derived.hasIsModifierReasonElement()) - derived.getIsModifierReasonElement().setUserData(UD_DERIVATION_EQUALS, true); + derived.getIsModifierReasonElement().setUserData(UserDataNames.SNAPSHOT_DERIVATION_EQUALS, true); } boolean hasBinding = derived.hasBinding(); @@ -2830,7 +2825,7 @@ public class ProfileUtilities { } else if (trimDifferential) derived.setBinding(null); else - derived.getBinding().setUserData(UD_DERIVATION_EQUALS, true); + derived.getBinding().setUserData(UserDataNames.SNAPSHOT_DERIVATION_EQUALS, true); } else if (base.hasBinding()) { base.getBinding().getExtension().removeIf(ext -> Utilities.existsInList(ext.getUrl(), ProfileUtilities.NON_INHERITED_ED_URLS)); } @@ -2843,7 +2838,7 @@ public class ProfileUtilities { } else if (trimDifferential) derived.setIsSummaryElement(null); else - derived.getIsSummaryElement().setUserData(UD_DERIVATION_EQUALS, true); + derived.getIsSummaryElement().setUserData(UserDataNames.SNAPSHOT_DERIVATION_EQUALS, true); } if (derived.hasType()) { @@ -2864,14 +2859,14 @@ public class ProfileUtilities { derived.getType().clear(); else for (TypeRefComponent t : derived.getType()) - t.setUserData(UD_DERIVATION_EQUALS, true); + t.setUserData(UserDataNames.SNAPSHOT_DERIVATION_EQUALS, true); } mappings.merge(derived, base); // note reversal of names to be correct in .merge() // todo: constraints are cumulative. there is no replacing for (ElementDefinitionConstraintComponent s : base.getConstraint()) { - s.setUserData(UD_IS_DERIVED, true); + s.setUserData(UserDataNames.SNAPSHOT_IS_DERIVED, true); if (!s.hasSource()) { s.setSource(srcSD.getUrl()); } @@ -3505,7 +3500,7 @@ public class ProfileUtilities { public void sortDifferential(StructureDefinition base, StructureDefinition diff, String name, List errors, boolean errorIfChanges) throws FHIRException { int index = 0; for (ElementDefinition ed : diff.getDifferential().getElement()) { - ed.setUserData("ed.index", Integer.toString(index)); + ed.setUserData(UserDataNames.SNAPSHOT_SORT_ed_index, Integer.toString(index)); index++; } List original = new ArrayList<>(); @@ -3565,7 +3560,7 @@ public class ProfileUtilities { ElementDefinition e = diffList.get(i); ElementDefinition n = newDiff.get(i); if (!n.getPath().equals(e.getPath())) { - errors.add("The element "+(e.hasId() ? e.getId() : e.getPath())+" @diff["+e.getUserString("ed.index")+"] is out of order (and maybe others after it)"); + errors.add("The element "+(e.hasId() ? e.getId() : e.getPath())+" @diff["+e.getUserString(UserDataNames.SNAPSHOT_SORT_ed_index)+"] is out of order (and maybe others after it)"); return; } } @@ -4252,8 +4247,8 @@ public class ProfileUtilities { // first, name them int i = 0; for (ElementDefinition ed : slices) { - if (ed.hasUserData("slice-name")) { - ed.setSliceName(ed.getUserString("slice-name")); + if (ed.hasUserData(UserDataNames.SNAPSHOT_slice_name)) { + ed.setSliceName(ed.getUserString(UserDataNames.SNAPSHOT_slice_name)); } else { i++; ed.setSliceName("slice-"+Integer.toString(i)); 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 c3feaac3a..1edaab81d 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 @@ -136,6 +136,7 @@ import org.hl7.fhir.r5.terminologies.client.TerminologyClientContext; import org.hl7.fhir.r5.utils.PackageHackerR5; import org.hl7.fhir.r5.utils.ResourceUtilities; import org.hl7.fhir.r5.utils.ToolingExtensions; +import org.hl7.fhir.r5.utils.UserDataNames; import org.hl7.fhir.r5.utils.client.EFhirClientException; import org.hl7.fhir.r5.utils.validation.ValidationContextCarrier; import org.hl7.fhir.utilities.FhirPublication; @@ -1116,7 +1117,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte } else { be.getRequest().setUrl("CodeSystem/$validate-code"); } - be.setUserData("source", codingValidationRequest); + be.setUserData(UserDataNames.TX_REQUEST, codingValidationRequest); systems.add(codingValidationRequest.getCoding().getSystem()); findRelevantSystems(systems, codingValidationRequest.getCoding()); } @@ -1126,7 +1127,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte TerminologyClientContext tc = terminologyClientManager.chooseServer(vs, systems, false); Bundle resp = processBatch(tc, batch, systems); for (int i = 0; i < batch.getEntry().size(); i++) { - CodingValidationRequest t = (CodingValidationRequest) batch.getEntry().get(i).getUserData("source"); + CodingValidationRequest t = (CodingValidationRequest) batch.getEntry().get(i).getUserData(UserDataNames.TX_REQUEST); BundleEntryComponent r = resp.getEntry().get(i); if (r.getResource() instanceof Parameters) { @@ -1224,7 +1225,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte } else { be.getRequest().setUrl("CodeSystem/$validate-code"); } - be.setUserData("source", codingValidationRequest); + be.setUserData(UserDataNames.TX_REQUEST, codingValidationRequest); systems.add(codingValidationRequest.getCoding().getSystem()); } } @@ -1233,7 +1234,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte if (batch.getEntry().size() > 0) { Bundle resp = processBatch(tc, batch, systems); for (int i = 0; i < batch.getEntry().size(); i++) { - CodingValidationRequest t = (CodingValidationRequest) batch.getEntry().get(i).getUserData("source"); + CodingValidationRequest t = (CodingValidationRequest) batch.getEntry().get(i).getUserData(UserDataNames.TX_REQUEST); BundleEntryComponent r = resp.getEntry().get(i); if (r.getResource() instanceof Parameters) { @@ -3275,7 +3276,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte web = Utilities.pathURL(svs.getServer(), "ValueSet", svs.getVs().getIdBase()); } svs.getVs().setWebPath(web); - svs.getVs().setUserData("External.Link", svs.getServer()); // so we can render it differently + svs.getVs().setUserData(UserDataNames.render_external_link, svs.getServer()); // so we can render it differently } if (svs == null) { return null; @@ -3297,7 +3298,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte web = Utilities.pathURL(scs.getServer(), "ValueSet", scs.getCs().getIdBase()); } scs.getCs().setWebPath(web); - scs.getCs().setUserData("External.Link", scs.getServer()); // so we can render it differently + scs.getCs().setUserData(UserDataNames.render_external_link, scs.getServer()); // so we can render it differently } if (scs == null) { return null; diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/ContextUtilities.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/ContextUtilities.java index 12bc847a2..390bb1a25 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/ContextUtilities.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/ContextUtilities.java @@ -26,6 +26,7 @@ import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind; import org.hl7.fhir.r5.model.StructureDefinition.TypeDerivationRule; import org.hl7.fhir.r5.model.StructureMap; import org.hl7.fhir.r5.utils.ToolingExtensions; +import org.hl7.fhir.r5.utils.UserDataNames; import org.hl7.fhir.r5.utils.XVerExtensionManager; import org.hl7.fhir.r5.model.Identifier; import org.hl7.fhir.r5.model.NamingSystem; @@ -278,7 +279,7 @@ public class ContextUtilities implements ProfileKnowledgeProvider { for (String err : errors) { msgs.add(new ValidationMessage(Source.ProfileValidator, IssueType.EXCEPTION, p.getWebPath(), "Error sorting Differential: "+err, ValidationMessage.IssueSeverity.ERROR)); } - pu.generateSnapshot(sd, p, p.getUrl(), sd.getUserString("webroot"), p.getName()); + pu.generateSnapshot(sd, p, p.getUrl(), sd.getUserString(UserDataNames.render_webroot), p.getName()); for (ValidationMessage msg : msgs) { if ((!ProfileUtilities.isSuppressIgnorableExceptions() && msg.getLevel() == ValidationMessage.IssueSeverity.ERROR) || msg.getLevel() == ValidationMessage.IssueSeverity.FATAL) { if (!msg.isIgnorableError()) { @@ -298,9 +299,9 @@ public class ContextUtilities implements ProfileKnowledgeProvider { // work around the fact that some Implementation guides were published with old snapshot generators that left invalid snapshots behind. private boolean isProfileNeedsRegenerate(StructureDefinition p) { - boolean needs = !p.hasUserData("hack.regnerated") && Utilities.existsInList(p.getUrl(), "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaireresponse"); + boolean needs = !p.hasUserData(UserDataNames.SNAPSHOT_regeneration_tracker) && Utilities.existsInList(p.getUrl(), "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaireresponse"); if (needs) { - p.setUserData("hack.regnerated", "yes"); + p.setUserData(UserDataNames.SNAPSHOT_regeneration_tracker, "yes"); } return needs; } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/SimpleWorkerContext.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/SimpleWorkerContext.java index e60feb7c4..cee46ecd8 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/SimpleWorkerContext.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/SimpleWorkerContext.java @@ -72,6 +72,7 @@ import org.hl7.fhir.r5.terminologies.client.TerminologyClientManager.ITerminolog import org.hl7.fhir.r5.terminologies.client.TerminologyClientR5; import org.hl7.fhir.r5.utils.validation.IResourceValidator; import org.hl7.fhir.r5.utils.R5Hacker; +import org.hl7.fhir.r5.utils.UserDataNames; import org.hl7.fhir.r5.utils.XVerExtensionManager; import org.hl7.fhir.utilities.ByteProvider; import org.hl7.fhir.utilities.MagicResources; @@ -620,7 +621,7 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon public List getResourceNames() { Set result = new HashSet(); for (StructureDefinition sd : listStructures()) { - if (sd.getKind() == StructureDefinitionKind.RESOURCE && sd.getDerivation() == TypeDerivationRule.SPECIALIZATION && !sd.hasUserData("old.load.mode")) + if (sd.getKind() == StructureDefinitionKind.RESOURCE && sd.getDerivation() == TypeDerivationRule.SPECIALIZATION && !sd.hasUserData(UserDataNames.loader_urls_patched)) result.add(sd.getName()); } return Utilities.sorted(result); 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 31e90c933..7d0b7a6e1 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 @@ -54,6 +54,7 @@ import org.hl7.fhir.r5.model.TypeConvertor; import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent; import org.hl7.fhir.r5.terminologies.expansion.ValueSetExpansionOutcome; import org.hl7.fhir.r5.utils.ToolingExtensions; +import org.hl7.fhir.r5.utils.UserDataNames; import org.hl7.fhir.utilities.ElementDecoration; import org.hl7.fhir.utilities.ElementDecoration.DecorationType; import org.hl7.fhir.utilities.FhirPublication; @@ -691,7 +692,7 @@ public class Element extends Base implements NamedItem { } public void clearDecorations() { - clearUserData("fhir.decorations"); + clearUserData(UserDataNames.rendering_xml_decorations); for (Element e : children) { e.clearDecorations(); } @@ -699,10 +700,10 @@ public class Element extends Base implements NamedItem { public void markValidation(StructureDefinition profile, ElementDefinition definition) { @SuppressWarnings("unchecked") - List decorations = (List) getUserData("fhir.decorations"); + List decorations = (List) getUserData(UserDataNames.rendering_xml_decorations); if (decorations == null) { decorations = new ArrayList<>(); - setUserData("fhir.decorations", decorations); + setUserData(UserDataNames.rendering_xml_decorations, decorations); } decorations.add(new ElementDecoration(DecorationType.TYPE, profile.getWebPath(), definition.getPath())); if (definition.getId() != null && tail(definition.getId()).contains(":")) { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/LanguageUtils.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/LanguageUtils.java index b2c3646bd..44ecc181a 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/LanguageUtils.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/LanguageUtils.java @@ -28,6 +28,7 @@ import org.hl7.fhir.r5.model.StringType; import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.r5.terminologies.CodeSystemUtilities; import org.hl7.fhir.r5.utils.ToolingExtensions; +import org.hl7.fhir.r5.utils.UserDataNames; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.i18n.AcceptLanguageHeader; @@ -59,11 +60,6 @@ public class LanguageUtils { public static final List TRANSLATION_SUPPLEMENT_RESOURCE_TYPES = Arrays.asList("CodeSystem", "StructureDefinition", "Questionnaire"); - private static final String ORPHAN_TRANSLATIONS_NAME = "translations.orphans"; - - private static final String SUPPLEMENT_SOURCE_RESOURCE = "translations.supplemented"; - private static final String SUPPLEMENT_SOURCE_TRANSLATIONS = "translations.source-list"; - IWorkerContext context; private List crlist; @@ -401,8 +397,8 @@ public class LanguageUtils { } public void fillSupplement(CodeSystem csSrc, CodeSystem csDst, List list) { - csDst.setUserData(SUPPLEMENT_SOURCE_RESOURCE, csSrc); - csDst.setUserData(SUPPLEMENT_SOURCE_TRANSLATIONS, list); + csDst.setUserData(UserDataNames.LANGUTILS_SOURCE_SUPPLEMENT, csSrc); + csDst.setUserData(UserDataNames.LANGUTILS_SOURCE_TRANSLATIONS, list); for (TranslationUnit tu : list) { String code = tu.getId(); String subCode = null; @@ -458,10 +454,10 @@ public class LanguageUtils { } private void addOrphanTranslation(CodeSystem cs, TranslationUnit tu) { - List list = (List) cs.getUserData(ORPHAN_TRANSLATIONS_NAME); + List list = (List) cs.getUserData(UserDataNames.LANGUTILS_ORPHAN); if (list == null) { list = new ArrayList<>(); - cs.setUserData(ORPHAN_TRANSLATIONS_NAME, list); + cs.setUserData(UserDataNames.LANGUTILS_ORPHAN, list); } list.add(tu); } @@ -489,7 +485,7 @@ public class LanguageUtils { } public boolean handlesAsResource(Resource resource) { - return (resource instanceof CodeSystem && resource.hasUserData(SUPPLEMENT_SOURCE_RESOURCE)) || (resource instanceof StructureDefinition); + return (resource instanceof CodeSystem && resource.hasUserData(UserDataNames.LANGUTILS_SOURCE_SUPPLEMENT)) || (resource instanceof StructureDefinition); } public boolean handlesAsElement(Element element) { @@ -501,20 +497,20 @@ public class LanguageUtils { if (res instanceof StructureDefinition) { StructureDefinition sd = (StructureDefinition) res; generateTranslations(list, sd, lang); - if (res.hasUserData(ORPHAN_TRANSLATIONS_NAME)) { - List orphans = (List) res.getUserData(ORPHAN_TRANSLATIONS_NAME); + if (res.hasUserData(UserDataNames.LANGUTILS_ORPHAN)) { + List orphans = (List) res.getUserData(UserDataNames.LANGUTILS_ORPHAN); for (TranslationUnit t : orphans) { list.add(new TranslationUnit(lang, "!!"+t.getId(), t.getContext1(), t.getSrcText(), t.getTgtText())); } } } else { - CodeSystem cs = (CodeSystem) res.getUserData(SUPPLEMENT_SOURCE_RESOURCE); - List inputs = res.hasUserData(SUPPLEMENT_SOURCE_TRANSLATIONS) ? (List) res.getUserData(SUPPLEMENT_SOURCE_TRANSLATIONS) : new ArrayList<>(); + CodeSystem cs = (CodeSystem) res.getUserData(UserDataNames.LANGUTILS_SOURCE_SUPPLEMENT); + List inputs = res.hasUserData(UserDataNames.LANGUTILS_SOURCE_TRANSLATIONS) ? (List) res.getUserData(UserDataNames.LANGUTILS_SOURCE_TRANSLATIONS) : new ArrayList<>(); for (ConceptDefinitionComponent cd : cs.getConcept()) { generateTranslations(list, cd, lang, inputs); } - if (cs.hasUserData(ORPHAN_TRANSLATIONS_NAME)) { - List orphans = (List) cs.getUserData(ORPHAN_TRANSLATIONS_NAME); + if (cs.hasUserData(UserDataNames.LANGUTILS_ORPHAN)) { + List orphans = (List) cs.getUserData(UserDataNames.LANGUTILS_ORPHAN); for (TranslationUnit t : orphans) { list.add(new TranslationUnit(lang, "!!"+t.getId(), t.getContext1(), t.getSrcText(), t.getTgtText())); } 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 3d7f43a64..f8d71765b 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 @@ -66,6 +66,7 @@ import org.hl7.fhir.r5.model.ElementDefinition.PropertyRepresentation; import org.hl7.fhir.r5.model.Enumeration; import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.r5.utils.ToolingExtensions; +import org.hl7.fhir.r5.utils.UserDataNames; import org.hl7.fhir.r5.utils.formats.XmlLocationAnnotator; import org.hl7.fhir.r5.utils.formats.XmlLocationData; import org.hl7.fhir.utilities.ElementDecoration; @@ -802,7 +803,7 @@ public class XmlParser extends ParserBase { if (!(isElideElements() && element.isElided())) { if (showDecorations) { @SuppressWarnings("unchecked") - List decorations = (List) element.getUserData("fhir.decorations"); + List decorations = (List) element.getUserData(UserDataNames.rendering_xml_decorations); if (decorations != null) for (ElementDecoration d : decorations) xml.decorate(d); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/CanonicalResource.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/CanonicalResource.java index b874cf138..ce3ef95fd 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/CanonicalResource.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/CanonicalResource.java @@ -36,6 +36,7 @@ import java.util.Date; import java.util.List; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.r5.model.Enumerations.*; +import org.hl7.fhir.r5.utils.UserDataNames; import org.hl7.fhir.instance.model.api.IBaseBackboneElement; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.instance.model.api.ICompositeType; @@ -596,8 +597,8 @@ public abstract class CanonicalResource extends DomainResource { } public String present() { - if (hasUserData("presentation")) { - return getUserString("presentation"); + if (hasUserData(UserDataNames.render_presentation)) { + return getUserString(UserDataNames.render_presentation); } if (hasTitle()) return getTitle(); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/gen/PECodeGenerator.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/gen/PECodeGenerator.java index 9ed54b0a3..8abcf88f0 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/gen/PECodeGenerator.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/gen/PECodeGenerator.java @@ -53,6 +53,7 @@ import org.hl7.fhir.r5.profilemodel.PEBuilder; import org.hl7.fhir.r5.profilemodel.PEBuilder.PEElementPropertiesPolicy; import org.hl7.fhir.r5.profilemodel.gen.PECodeGenerator.ExtensionPolicy; import org.hl7.fhir.r5.terminologies.expansion.ValueSetExpansionOutcome; +import org.hl7.fhir.r5.utils.UserDataNames; import org.hl7.fhir.r5.profilemodel.PEDefinition; import org.hl7.fhir.r5.profilemodel.PEInstance; import org.hl7.fhir.r5.profilemodel.PEType; @@ -261,14 +262,14 @@ public class PECodeGenerator { if (cc.getAbstract()) { code = "_"+code; } - cc.setUserData("java.code", code); + cc.setUserData(UserDataNames.java_code, code); w(enums, " "+code+(i < vse.getValueset().getExpansion().getContains().size() - 1 ? "," : ";")+" // \""+cc.getDisplay()+"\" = "+cc.getSystem()+"#"+cc.getCode()); } w(enums, ""); w(enums, " public static "+name+" fromCode(String s) {"); w(enums, " switch (s) {"); for (ValueSetExpansionContainsComponent cc : vse.getValueset().getExpansion().getContains()) { - w(enums, " case \""+cc.getCode()+"\": return "+cc.getUserString("java.code")+";"); + w(enums, " case \""+cc.getCode()+"\": return "+cc.getUserString(UserDataNames.java_code)+";"); } w(enums, " default: return null;"); w(enums, " }"); @@ -281,7 +282,7 @@ public class PECodeGenerator { } else { w(enums, " if (\""+cc.getSystem()+"\".equals(c.getSystem()) && \""+cc.getCode()+"\".equals(c.getCode())) {"); } - w(enums, " return "+cc.getUserString("java.code")+";"); + w(enums, " return "+cc.getUserString(UserDataNames.java_code)+";"); w(enums, " }"); } w(enums, " return null;"); @@ -301,7 +302,7 @@ public class PECodeGenerator { w(enums, " public String toDisplay() {"); w(enums, " switch (this) {"); for (ValueSetExpansionContainsComponent cc : vse.getValueset().getExpansion().getContains()) { - w(enums, " case "+cc.getUserString("java.code")+": return \""+Utilities.escapeJava(cc.getDisplay())+"\";"); + w(enums, " case "+cc.getUserString(UserDataNames.java_code)+": return \""+Utilities.escapeJava(cc.getDisplay())+"\";"); } w(enums, " default: return null;"); w(enums, " }"); @@ -311,7 +312,7 @@ public class PECodeGenerator { w(enums, " public String toCode() {"); w(enums, " switch (this) {"); for (ValueSetExpansionContainsComponent cc : vse.getValueset().getExpansion().getContains()) { - w(enums, " case "+cc.getUserString("java.code")+": return \""+cc.getCode()+"\";"); + w(enums, " case "+cc.getUserString(UserDataNames.java_code)+": return \""+cc.getCode()+"\";"); } w(enums, " default: return null;"); w(enums, " }"); @@ -321,9 +322,9 @@ public class PECodeGenerator { w(enums, " switch (this) {"); for (ValueSetExpansionContainsComponent cc : vse.getValueset().getExpansion().getContains()) { if (cc.hasVersion()) { - w(enums, " case "+cc.getUserString("java.code")+": return new Coding().setSystem(\""+cc.getSystem()+"\").setVersion(\""+cc.getVersion()+"\").setCode()\""+cc.getCode()+"\";"); + w(enums, " case "+cc.getUserString(UserDataNames.java_code)+": return new Coding().setSystem(\""+cc.getSystem()+"\").setVersion(\""+cc.getVersion()+"\").setCode()\""+cc.getCode()+"\";"); } else { - w(enums, " case "+cc.getUserString("java.code")+": return new Coding().setSystem(\""+cc.getSystem()+"\").setCode(\""+cc.getCode()+"\");"); + w(enums, " case "+cc.getUserString(UserDataNames.java_code)+": return new Coding().setSystem(\""+cc.getSystem()+"\").setCode(\""+cc.getCode()+"\");"); } } w(enums, " default: return null;"); 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 519489942..dda244f1c 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 @@ -20,6 +20,7 @@ import org.hl7.fhir.r5.model.ValueSet; import org.hl7.fhir.r5.renderers.CodeResolver.CodeResolution; import org.hl7.fhir.r5.renderers.Renderer.RenderingStatus; import org.hl7.fhir.r5.renderers.utils.RenderingContext; +import org.hl7.fhir.r5.utils.UserDataNames; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.VersionUtilities; import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator; @@ -117,7 +118,7 @@ public class AdditionalBindingsRenderer { abr.compare = new AdditionalBindingDetail(); abr.compare.valueSet = compExt==null ? null : compExt.getValue().primitiveValue(); } else { - abr.isUnchanged = ext.hasUserData(ProfileUtilities.UD_DERIVATION_EQUALS); + abr.isUnchanged = ext.hasUserData(UserDataNames.SNAPSHOT_DERIVATION_EQUALS); } bindings.add(abr); } @@ -181,7 +182,7 @@ public class AdditionalBindingsRenderer { } } abr.any = "any".equals(ext.getExtensionString("scope")); - abr.isUnchanged = ext.hasUserData(ProfileUtilities.UD_DERIVATION_EQUALS); + abr.isUnchanged = ext.hasUserData(UserDataNames.SNAPSHOT_DERIVATION_EQUALS); return abr; } @@ -193,7 +194,7 @@ public class AdditionalBindingsRenderer { abr.docoShort = ab.getShortDoco(); abr.usages.addAll(ab.getUsage()); abr.any = ab.getAny(); - abr.isUnchanged = ab.hasUserData(ProfileUtilities.UD_DERIVATION_EQUALS); + abr.isUnchanged = ab.hasUserData(UserDataNames.SNAPSHOT_DERIVATION_EQUALS); return abr; } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/CodeSystemRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/CodeSystemRenderer.java index dfcaf5c30..42e852683 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/CodeSystemRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/CodeSystemRenderer.java @@ -35,6 +35,7 @@ import org.hl7.fhir.r5.terminologies.CodeSystemUtilities; import org.hl7.fhir.r5.terminologies.CodeSystemUtilities.CodeSystemNavigator; import org.hl7.fhir.r5.utils.EOperationOutcome; import org.hl7.fhir.r5.utils.ToolingExtensions; +import org.hl7.fhir.r5.utils.UserDataNames; import org.hl7.fhir.utilities.LoincLinker; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.xhtml.XhtmlNode; @@ -409,7 +410,7 @@ public class CodeSystemRenderer extends TerminologyRenderer { } private boolean conceptsHaveVersion(ConceptDefinitionComponent c) { - if (c.hasUserData("cs.version.notes")) + if (c.hasUserData(UserDataNames.tx_cs_version_notes)) return true; for (ConceptDefinitionComponent g : c.getConcept()) if (conceptsHaveVersion(g)) @@ -567,8 +568,9 @@ public class CodeSystemRenderer extends TerminologyRenderer { } if (version) { td = tr.td(); - if (c.hasUserData("cs.version.notes")) - td.addText(c.getUserString("cs.version.notes")); + if (c.hasUserData(UserDataNames.tx_cs_version_notes)) { // todo: this is never set + td.addText(c.getUserString(UserDataNames.tx_cs_version_notes)); + } } if (properties != null) { for (PropertyComponent pc : properties) { 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 5ab91bd44..c1f2f3b2f 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 @@ -50,6 +50,7 @@ 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.r5.utils.UserDataNames; import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.VersionUtilities; @@ -148,7 +149,7 @@ public class DataRenderer extends Renderer implements CodeResolver { } url = p.getWebPath(); if (url == null) { - url = p.getUserString("filename"); + url = p.getUserString(UserDataNames.render_filename); } } else { throw new DefinitionException(context.formatPhrase(RenderingContext.DATA_REND_MKDWN_LNK, link) + " "); @@ -261,8 +262,8 @@ public class DataRenderer extends Renderer implements CodeResolver { } private String crPresent(CanonicalResource cr) { - if (cr.hasUserData("presentation")) { - return cr.getUserString("presentation"); + if (cr.hasUserData(UserDataNames.render_presentation)) { + return cr.getUserString(UserDataNames.render_presentation); } if (cr.hasTitle()) return context.getTranslated(cr.getTitleElement()); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ObligationsRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ObligationsRenderer.java index 265c22d17..168718ca5 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ObligationsRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ObligationsRenderer.java @@ -19,6 +19,7 @@ import org.hl7.fhir.r5.model.ValueSet; import org.hl7.fhir.r5.renderers.CodeResolver.CodeResolution; import org.hl7.fhir.r5.renderers.utils.RenderingContext; import org.hl7.fhir.r5.renderers.utils.ResourceWrapper; +import org.hl7.fhir.r5.utils.UserDataNames; import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator; import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Cell; import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Piece; @@ -65,7 +66,7 @@ public class ObligationsRenderer extends Renderer { for (Extension eid : ext.getExtensionsByUrl("elementId")) { this.elementIds.add(eid.getValue().primitiveValue()); } - this.isUnchanged = ext.hasUserData(ProfileUtilities.UD_DERIVATION_EQUALS); + this.isUnchanged = ext.hasUserData(UserDataNames.SNAPSHOT_DERIVATION_EQUALS); } private String getKey() { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/Renderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/Renderer.java index 45f1de84f..9e5d586fc 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/Renderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/Renderer.java @@ -12,6 +12,7 @@ import org.hl7.fhir.r5.renderers.utils.RenderingContext; import org.hl7.fhir.r5.renderers.utils.RenderingContext.GenerationRules; import org.hl7.fhir.r5.renderers.utils.RenderingContext.KnownLinkType; import org.hl7.fhir.r5.renderers.utils.RenderingContext.ResourceRendererMode; +import org.hl7.fhir.r5.utils.UserDataNames; import org.hl7.fhir.r5.renderers.utils.ResourceWrapper; import org.hl7.fhir.utilities.MarkDownProcessor; import org.hl7.fhir.utilities.MarkDownProcessor.Dialect; @@ -87,7 +88,7 @@ public class Renderer { if (b == null || context.getChangeVersion() == null) { return x; } - VersionComparisonAnnotation vca = (VersionComparisonAnnotation) b.getUserData(VersionComparisonAnnotation.USER_DATA_NAME); + VersionComparisonAnnotation vca = (VersionComparisonAnnotation) b.getUserData(UserDataNames.COMP_VERSION_ANNOTATION); if (vca == null) { return x; } @@ -119,7 +120,7 @@ public class Renderer { if (b == null || context.getChangeVersion() == null) { return x; } - VersionComparisonAnnotation vca = (VersionComparisonAnnotation) b.getUserData(VersionComparisonAnnotation.USER_DATA_NAME); + VersionComparisonAnnotation vca = (VersionComparisonAnnotation) b.getUserData(UserDataNames.COMP_VERSION_ANNOTATION); if (vca == null) { return x; } @@ -152,7 +153,7 @@ public class Renderer { if (b == null || context.getChangeVersion() == null) { return tr.td(); } - VersionComparisonAnnotation vca = (VersionComparisonAnnotation) b.getUserData(VersionComparisonAnnotation.USER_DATA_NAME); + VersionComparisonAnnotation vca = (VersionComparisonAnnotation) b.getUserData(UserDataNames.COMP_VERSION_ANNOTATION); if (vca == null) { return tr.td(); } @@ -191,8 +192,8 @@ public class Renderer { } public static void renderStatusSummary(RenderingContext context, Base base, XhtmlNode x, String version, String... metadataFields) { - if (base.hasUserData(VersionComparisonAnnotation.USER_DATA_NAME)) { - VersionComparisonAnnotation self = (VersionComparisonAnnotation) base.getUserData(VersionComparisonAnnotation.USER_DATA_NAME); + if (base.hasUserData(UserDataNames.COMP_VERSION_ANNOTATION)) { + VersionComparisonAnnotation self = (VersionComparisonAnnotation) base.getUserData(UserDataNames.COMP_VERSION_ANNOTATION); switch (self.getType()) { case Added: XhtmlNode spanInner = x.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", context.formatPhrase(RenderingContext.REND_SINCE_ADDED, version)); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/StructureDefinitionRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/StructureDefinitionRenderer.java index 100c00112..12c4e922d 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/StructureDefinitionRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/StructureDefinitionRenderer.java @@ -75,6 +75,7 @@ import org.hl7.fhir.r5.terminologies.utilities.ValidationResult; import org.hl7.fhir.r5.utils.EOperationOutcome; import org.hl7.fhir.r5.utils.PublicationHacker; import org.hl7.fhir.r5.utils.ToolingExtensions; +import org.hl7.fhir.r5.utils.UserDataNames; import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; import org.hl7.fhir.utilities.MarkDownProcessor; import org.hl7.fhir.utilities.StandardsStatus; @@ -292,8 +293,8 @@ public class StructureDefinitionRenderer extends ResourceRenderer { } public void renderDetails(XhtmlNode f) { - if (value.hasUserData("render.link")) { - f = f.ah(context.prefixLocalHref(value.getUserString("render.link"))); + if (value.hasUserData(UserDataNames.render_link)) { + f = f.ah(context.prefixLocalHref(value.getUserString(UserDataNames.render_link))); } f.tx(value.asStringValue()); } @@ -312,8 +313,8 @@ public class StructureDefinitionRenderer extends ResourceRenderer { public void renderDetails(XhtmlNode f) throws IOException { - if (value.hasUserData("render.link")) { - f = f.ah(context.prefixLocalHref(value.getUserString("render.link"))); + if (value.hasUserData(UserDataNames.render_link)) { + f = f.ah(context.prefixLocalHref(value.getUserString(UserDataNames.render_link))); } f.tx(summarize(value)); } @@ -777,7 +778,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer { } else { row.setIcon("icon_resource.png", context.formatPhrase(RenderingContext.GENERAL_RESOURCE)); } - if (element.hasUserData("render.opaque")) { + if (element.hasUserData(UserDataNames.render_opaque)) { row.setOpacity("0.5"); } UnusedTracker used = new UnusedTracker(); @@ -790,8 +791,8 @@ public class StructureDefinitionRenderer extends ResourceRenderer { if (logicalModel) { if (element.hasRepresentation(PropertyRepresentation.XMLATTR)) { sName = "@"+sName; - } else if (element.hasUserData("derived.pointer")) { - ElementDefinition drv = (ElementDefinition) element.getUserData("derived.pointer"); + } else if (element.hasUserData(UserDataNames.SNAPSHOT_DERIVATION_POINTER)) { + ElementDefinition drv = (ElementDefinition) element.getUserData(UserDataNames.SNAPSHOT_DERIVATION_POINTER); if (drv.hasRepresentation(PropertyRepresentation.XMLATTR)) { sName = "@"+sName; } @@ -969,7 +970,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer { } private boolean isTypeSlice(ElementDefinition child) { - ElementDefinition derived = (ElementDefinition) child.getUserData("derived.pointer"); + ElementDefinition derived = (ElementDefinition) child.getUserData(UserDataNames.SNAPSHOT_DERIVATION_POINTER); return derived != null && derived.getBase().getPath().endsWith("[x]"); } @@ -1138,7 +1139,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer { if (extDefn == null) { res.add(genCardinality(gen, element, row, hasDef, used, null)); res.add(addCell(row, gen.new Cell(null, null, "?gen-e1? "+element.getType().get(0).getProfile(), null, null))); - res.add(generateDescription(status, gen, row, element, (ElementDefinition) element.getUserData(ProfileUtilities.UD_DERIVATION_POINTER), used.used, profile == null ? "" : profile.getUrl(), eurl, profile, corePath, imagePath, root, logicalModel, allInvariants, snapshot, mustSupport, allowSubRows, rc, inScopeElements, resource)); + res.add(generateDescription(status, gen, row, element, (ElementDefinition) element.getUserData(UserDataNames.SNAPSHOT_DERIVATION_POINTER), used.used, profile == null ? "" : profile.getUrl(), eurl, profile, corePath, imagePath, root, logicalModel, allInvariants, snapshot, mustSupport, allowSubRows, rc, inScopeElements, resource)); } else { String name = element.hasSliceName() ? element.getSliceName() : urltail(eurl); nameCell.getPieces().get(0).setText(name); @@ -1159,7 +1160,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer { res.add(addCell(row, gen.new Cell())); else res.add(genTypes(gen, row, element, profileBaseFileName, profile, corePath, imagePath, root, mustSupport)); - res.add(generateDescription(status, gen, row, element, (ElementDefinition) element.getUserData(ProfileUtilities.UD_DERIVATION_POINTER), used.used, null, null, profile, corePath, imagePath, root, logicalModel, allInvariants, snapshot, mustSupport, allowSubRows, rc, inScopeElements, resource)); + res.add(generateDescription(status, gen, row, element, (ElementDefinition) element.getUserData(UserDataNames.SNAPSHOT_DERIVATION_POINTER), used.used, null, null, profile, corePath, imagePath, root, logicalModel, allInvariants, snapshot, mustSupport, allowSubRows, rc, inScopeElements, resource)); } } } else if (element != null) { @@ -1168,7 +1169,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer { res.add(genTypes(gen, row, element, profileBaseFileName, profile, corePath, imagePath, root, mustSupport)); else res.add(addCell(row, gen.new Cell())); - res.add(generateDescription(status, gen, row, element, (ElementDefinition) element.getUserData(ProfileUtilities.UD_DERIVATION_POINTER), used.used, null, null, profile, corePath, imagePath, root, logicalModel, allInvariants, snapshot, mustSupport, allowSubRows, rc, inScopeElements, resource)); + res.add(generateDescription(status, gen, row, element, (ElementDefinition) element.getUserData(UserDataNames.SNAPSHOT_DERIVATION_POINTER), used.used, null, null, profile, corePath, imagePath, root, logicalModel, allInvariants, snapshot, mustSupport, allowSubRows, rc, inScopeElements, resource)); } return res; } @@ -1176,18 +1177,18 @@ public class StructureDefinitionRenderer extends ResourceRenderer { private Cell genCardinality(HierarchicalTableGenerator gen, ElementDefinition definition, Row row, boolean hasDef, UnusedTracker tracker, ElementDefinition fallback) { IntegerType min = !hasDef ? new IntegerType() : definition.hasMinElement() ? definition.getMinElement() : new IntegerType(); StringType max = !hasDef ? new StringType() : definition.hasMaxElement() ? definition.getMaxElement() : new StringType(); - if (min.isEmpty() && definition.getUserData(ProfileUtilities.UD_DERIVATION_POINTER) != null) { - ElementDefinition base = (ElementDefinition) definition.getUserData(ProfileUtilities.UD_DERIVATION_POINTER); + if (min.isEmpty() && definition.getUserData(UserDataNames.SNAPSHOT_DERIVATION_POINTER) != null) { + ElementDefinition base = (ElementDefinition) definition.getUserData(UserDataNames.SNAPSHOT_DERIVATION_POINTER); if (base.hasMinElement()) { min = base.getMinElement().copy(); - min.setUserData(ProfileUtilities.UD_DERIVATION_EQUALS, true); + min.setUserData(UserDataNames.SNAPSHOT_DERIVATION_EQUALS, true); } } - if (max.isEmpty() && definition.getUserData(ProfileUtilities.UD_DERIVATION_POINTER) != null) { - ElementDefinition base = (ElementDefinition) definition.getUserData(ProfileUtilities.UD_DERIVATION_POINTER); + if (max.isEmpty() && definition.getUserData(UserDataNames.SNAPSHOT_DERIVATION_POINTER) != null) { + ElementDefinition base = (ElementDefinition) definition.getUserData(UserDataNames.SNAPSHOT_DERIVATION_POINTER); if (base.hasMaxElement()) { max = base.getMaxElement().copy(); - max.setUserData(ProfileUtilities.UD_DERIVATION_EQUALS, true); + max.setUserData(UserDataNames.SNAPSHOT_DERIVATION_EQUALS, true); } } if (min.isEmpty() && fallback != null) @@ -1848,14 +1849,14 @@ public class StructureDefinitionRenderer extends ResourceRenderer { } private Piece checkForNoChange(Element source, Piece piece) { - if (source.hasUserData(ProfileUtilities.UD_DERIVATION_EQUALS)) { + if (source.hasUserData(UserDataNames.SNAPSHOT_DERIVATION_EQUALS)) { piece.addStyle("opacity: 0.5"); } return piece; } private String checkForNoChange(Element source) { - if (source.hasUserData(ProfileUtilities.UD_DERIVATION_EQUALS)) { + if (source.hasUserData(UserDataNames.SNAPSHOT_DERIVATION_EQUALS)) { return "opacity: 0.5"; } else { return null; @@ -1899,12 +1900,12 @@ public class StructureDefinitionRenderer extends ResourceRenderer { } else if (e.hasContentReference()) { return c; } else { - ElementDefinition d = (ElementDefinition) e.getUserData(ProfileUtilities.UD_DERIVATION_POINTER); + ElementDefinition d = (ElementDefinition) e.getUserData(UserDataNames.SNAPSHOT_DERIVATION_POINTER); if (d != null && d.hasType()) { types = new ArrayList(); for (TypeRefComponent tr : d.getType()) { TypeRefComponent tt = tr.copy(); - tt.setUserData(ProfileUtilities.UD_DERIVATION_EQUALS, true); + tt.setUserData(UserDataNames.SNAPSHOT_DERIVATION_EQUALS, true); types.add(tt); } } else { @@ -2281,33 +2282,33 @@ public class StructureDefinitionRenderer extends ResourceRenderer { } private ElementDefinitionBindingComponent makeUnifiedBinding(ElementDefinitionBindingComponent binding, ElementDefinition element) { - if (!element.hasUserData(ProfileUtilities.UD_DERIVATION_POINTER)) { + if (!element.hasUserData(UserDataNames.SNAPSHOT_DERIVATION_POINTER)) { return binding; } - ElementDefinition base = (ElementDefinition) element.getUserData(ProfileUtilities.UD_DERIVATION_POINTER); + ElementDefinition base = (ElementDefinition) element.getUserData(UserDataNames.SNAPSHOT_DERIVATION_POINTER); if (!base.hasBinding()) { return binding; } ElementDefinitionBindingComponent o = base.getBinding(); ElementDefinitionBindingComponent b = new ElementDefinitionBindingComponent(); - b.setUserData(ProfileUtilities.UD_DERIVATION_POINTER, o); + b.setUserData(UserDataNames.SNAPSHOT_DERIVATION_POINTER, o); if (binding.hasValueSet()) { b.setValueSet(binding.getValueSet()); } else if (o.hasValueSet()) { b.setValueSet(o.getValueSet()); - b.getValueSetElement().setUserData(ProfileUtilities.UD_DERIVATION_EQUALS, o.getValueSetElement()); + b.getValueSetElement().setUserData(UserDataNames.SNAPSHOT_DERIVATION_EQUALS, o.getValueSetElement()); } if (binding.hasStrength()) { b.setStrength(binding.getStrength()); } else if (o.hasStrength()) { b.setStrength(o.getStrength()); - b.getStrengthElement().setUserData(ProfileUtilities.UD_DERIVATION_EQUALS, o.getStrengthElement()); + b.getStrengthElement().setUserData(UserDataNames.SNAPSHOT_DERIVATION_EQUALS, o.getStrengthElement()); } if (binding.hasDescription()) { b.setDescription(binding.getDescription()); } else if (o.hasDescription()) { b.setDescription(o.getDescription()); - b.getDescriptionElement().setUserData(ProfileUtilities.UD_DERIVATION_EQUALS, o.getDescriptionElement()); + b.getDescriptionElement().setUserData(UserDataNames.SNAPSHOT_DERIVATION_EQUALS, o.getDescriptionElement()); } // todo: derivation? b.getExtension().addAll(binding.getExtension()); @@ -2913,7 +2914,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer { } private Piece checkForNoChange(Element src1, Element src2, Piece piece) { - if (src1.hasUserData(ProfileUtilities.UD_DERIVATION_EQUALS) && src2.hasUserData(ProfileUtilities.UD_DERIVATION_EQUALS)) { + if (src1.hasUserData(UserDataNames.SNAPSHOT_DERIVATION_EQUALS) && src2.hasUserData(UserDataNames.SNAPSHOT_DERIVATION_EQUALS)) { piece.addStyle("opacity: 0.5"); } return piece; @@ -3460,7 +3461,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer { } sdCache = new HashMap(); sdMapCache.put(url, sdCache); - String webroot = sd.getUserString("webroot"); + String webroot = sd.getUserString(UserDataNames.render_webroot); for (ElementDefinition e : sd.getSnapshot().getElement()) { context.getProfileUtilities().updateURLs(sd.getUrl(), webroot, e, false); sdCache.put(e.getId(), e); @@ -3472,8 +3473,8 @@ public class StructureDefinitionRenderer extends ResourceRenderer { // Returns the ElementDefinition for the 'parent' of the current element private ElementDefinition getBaseElement(ElementDefinition e, String url) { - if (e.hasUserData(ProfileUtilities.UD_DERIVATION_POINTER)) { - return getElementById(url, e.getUserString(ProfileUtilities.UD_DERIVATION_POINTER)); + if (e.hasUserData(UserDataNames.SNAPSHOT_DERIVATION_POINTER)) { + return getElementById(url, e.getUserString(UserDataNames.SNAPSHOT_DERIVATION_POINTER)); } return null; } @@ -3550,13 +3551,13 @@ public class StructureDefinitionRenderer extends ResourceRenderer { } else { // we delete it from the other @SuppressWarnings("unchecked") - List other = (List) allAnchors.get(s).getUserData("dict.generator.anchors"); + List other = (List) allAnchors.get(s).getUserData(UserDataNames.render_dict_generator_anchors); other.remove(s); allAnchors.put(s, ed); } } list.removeAll(removed); - ed.setUserData("dict.generator.anchors", list); + ed.setUserData(UserDataNames.render_dict_generator_anchors, list); } private void addToStack(List stack, ElementDefinition ec) { @@ -3571,7 +3572,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer { } private List makeAnchors(ElementDefinition ed, String anchorPrefix) { - List list = (List) ed.getUserData("dict.generator.anchors"); + List list = (List) ed.getUserData(UserDataNames.render_dict_generator_anchors); List res = new ArrayList<>(); res.add(anchorPrefix + ed.getId()); for (String s : list) { @@ -3908,7 +3909,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer { // gc.addStyledText("Standards Status = "+ss.toDisplay(), ss.getAbbrev(), "black", ss.getColor(), baseSpecUrl()+, true); StructureDefinition sdb = context.getContext().fetchResource(StructureDefinition.class, sd.getBaseDefinition()); if (sdb != null) { - StandardsStatus base = determineStandardsStatus(sdb, (ElementDefinition) d.getUserData("derived.pointer")); + StandardsStatus base = determineStandardsStatus(sdb, (ElementDefinition) d.getUserData(UserDataNames.SNAPSHOT_DERIVATION_POINTER)); if (base != null) { tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_STAND_STAT), "versions.html#std-process", strikethrough, ss.toDisplay()+" (from "+base.toDisplay()+")"); } else { @@ -4501,11 +4502,11 @@ public class StructureDefinitionRenderer extends ResourceRenderer { if (!t.getAggregation().isEmpty() || (compare!=null && !compare.getAggregation().isEmpty())) { for (Enumeration a :t.getAggregation()) { - a.setUserData("render.link", corePath + "codesystem-resource-aggregation-mode.html#content"); + a.setUserData(UserDataNames.render_link, corePath + "codesystem-resource-aggregation-mode.html#content"); } if (compare!=null) { for (Enumeration a : compare.getAggregation()) { - a.setUserData("render.link", corePath + "codesystem-resource-aggregation-mode.html#content"); + a.setUserData(UserDataNames.render_link, corePath + "codesystem-resource-aggregation-mode.html#content"); } } var xt = compareSimpleTypeLists(t.getAggregation(), compare == null ? null : compare.getAggregation(), mode); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/TerminologyRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/TerminologyRenderer.java index 1fcd82325..4b3ebe256 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/TerminologyRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/TerminologyRenderer.java @@ -25,6 +25,7 @@ import org.hl7.fhir.r5.renderers.utils.RenderingContext; import org.hl7.fhir.r5.terminologies.CodeSystemUtilities; import org.hl7.fhir.r5.terminologies.utilities.ValidationResult; import org.hl7.fhir.r5.utils.ToolingExtensions; +import org.hl7.fhir.r5.utils.UserDataNames; import org.hl7.fhir.utilities.CanonicalPair; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.xhtml.XhtmlNode; @@ -149,9 +150,9 @@ public abstract class TerminologyRenderer extends ResourceRenderer { String ref = null; boolean addHtml = true; if (cs != null) { - ref = (String) cs.getUserData("external.url"); + ref = (String) cs.getUserData(UserDataNames.render_external_link); if (Utilities.noString(ref)) - ref = (String) cs.getUserData("filename"); + ref = (String) cs.getUserData(UserDataNames.render_filename); else addHtml = false; if (Utilities.noString(ref)) { 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 729e5ae42..05d5b912d 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 @@ -55,6 +55,7 @@ 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; +import org.hl7.fhir.r5.utils.UserDataNames; import org.hl7.fhir.utilities.LoincLinker; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator; @@ -159,7 +160,7 @@ public class ValueSetRenderer extends TerminologyRenderer { // String url = ""; // ValueSet vsr = context.getWorker().findTxResource(ValueSet.class, ((Reference) a.getTarget()).getReference()); // if (vsr != null) -// url = (String) vsr.getUserData("filename"); +// url = (String) vsr.getUserData(UserDataNames.filename); // mymaps.put(a, url); // } // Map mymaps = new HashMap(); @@ -167,7 +168,7 @@ public class ValueSetRenderer extends TerminologyRenderer { // String url = ""; // ValueSet vsr = context.getWorker().fetchResource(ValueSet.class, ((Reference) a.getTarget()).getReference()); // if (vsr != null) -// url = (String) vsr.getUserData("filename"); +// url = (String) vsr.getUserData(UserDataNames.filename); // mymaps.put(a, url); // } // also, look in the contained resources for a concept map @@ -178,7 +179,7 @@ public class ValueSetRenderer extends TerminologyRenderer { // String url = ""; // ValueSet vsr = context.getWorker().findTxResource(ValueSet.class, ((Reference) cm.getTarget()).getReference()); // if (vsr != null) -// url = (String) vsr.getUserData("filename"); +// url = (String) vsr.getUserData(UserDataNames.filename); // mymaps.put(cm, url); // } // } @@ -753,7 +754,7 @@ public class ValueSetRenderer extends TerminologyRenderer { } String ref = cs.getWebPath(); if (ref == null) { - ref = cs.getUserString("filename"); + ref = cs.getUserString(UserDataNames.render_filename); } return ref == null ? null : ref.replace("\\", "/"); } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/CodeSystemUtilities.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/CodeSystemUtilities.java index 348d7e8cf..5e45c0a41 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/CodeSystemUtilities.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/CodeSystemUtilities.java @@ -67,6 +67,7 @@ import org.hl7.fhir.r5.model.StringType; import org.hl7.fhir.r5.model.UriType; import org.hl7.fhir.r5.utils.CanonicalResourceUtilities; import org.hl7.fhir.r5.utils.ToolingExtensions; +import org.hl7.fhir.r5.utils.UserDataNames; import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; import org.hl7.fhir.utilities.MarkDownProcessor; import org.hl7.fhir.utilities.StandardsStatus; @@ -590,11 +591,11 @@ public class CodeSystemUtilities extends TerminologyUtilities { if (ss == null || ss.isLowerThan(status)) ToolingExtensions.setStandardsStatus(cs, status, normativeVersion); if (pckage != null) { - if (!cs.hasUserData("ballot.package")) - cs.setUserData("ballot.package", pckage); - else if (!pckage.equals(cs.getUserString("ballot.package"))) - if (!"infrastructure".equals(cs.getUserString("ballot.package"))) - System.out.println("Code System "+cs.getUrl()+": ownership clash "+pckage+" vs "+cs.getUserString("ballot.package")); + if (!cs.hasUserData(UserDataNames.kindling_ballot_package)) + cs.setUserData(UserDataNames.kindling_ballot_package, pckage); + else if (!pckage.equals(cs.getUserString(UserDataNames.kindling_ballot_package))) + if (!"infrastructure".equals(cs.getUserString(UserDataNames.kindling_ballot_package))) + System.out.println("Code System "+cs.getUrl()+": ownership clash "+pckage+" vs "+cs.getUserString(UserDataNames.kindling_ballot_package)); } if (status == StandardsStatus.NORMATIVE) { cs.setExperimental(false); @@ -842,7 +843,7 @@ public class CodeSystemUtilities extends TerminologyUtilities { for (CodeSystem sup : supplements) { b.append(sup.getVersionedUrl()); } - ret.setUserData("supplements.installed", b.toString()); + ret.setUserData(UserDataNames.tx_known_supplements, b.toString()); for (ConceptDefinitionComponent t : ret.getConcept()) { mergeSupplements(ret, t, supplements); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/ValueSetUtilities.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/ValueSetUtilities.java index 479c9644e..d6a4ba06b 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/ValueSetUtilities.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/ValueSetUtilities.java @@ -67,6 +67,7 @@ import org.hl7.fhir.r5.terminologies.CodeSystemUtilities.ConceptDefinitionCompon import org.hl7.fhir.r5.terminologies.CodeSystemUtilities.ConceptStatus; import org.hl7.fhir.r5.utils.CanonicalResourceUtilities; import org.hl7.fhir.r5.utils.ToolingExtensions; +import org.hl7.fhir.r5.utils.UserDataNames; import org.hl7.fhir.utilities.StandardsStatus; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.VersionUtilities; @@ -167,7 +168,7 @@ public class ValueSetUtilities extends TerminologyUtilities { } public static void markStatus(ValueSet vs, String wg, StandardsStatus status, String pckage, String fmm, IWorkerContext context, String normativeVersion) throws FHIRException { - if (vs.hasUserData("external.url")) + if (vs.hasUserData(UserDataNames.render_external_link)) return; if (wg != null) { @@ -181,11 +182,11 @@ public class ValueSetUtilities extends TerminologyUtilities { if (ss == null || ss.isLowerThan(status)) ToolingExtensions.setStandardsStatus(vs, status, normativeVersion); if (pckage != null) { - if (!vs.hasUserData("ballot.package")) - vs.setUserData("ballot.package", pckage); - else if (!pckage.equals(vs.getUserString("ballot.package"))) - if (!"infrastructure".equals(vs.getUserString("ballot.package"))) - System.out.println("Value Set "+vs.getUrl()+": ownership clash "+pckage+" vs "+vs.getUserString("ballot.package")); + if (!vs.hasUserData(UserDataNames.kindling_ballot_package)) + vs.setUserData(UserDataNames.kindling_ballot_package, pckage); + else if (!pckage.equals(vs.getUserString(UserDataNames.kindling_ballot_package))) + if (!"infrastructure".equals(vs.getUserString(UserDataNames.kindling_ballot_package))) + System.out.println("Value Set "+vs.getUrl()+": ownership clash "+pckage+" vs "+vs.getUserString(UserDataNames.kindling_ballot_package)); } if (status == StandardsStatus.NORMATIVE) { vs.setExperimental(false); @@ -201,8 +202,8 @@ public class ValueSetUtilities extends TerminologyUtilities { vs.setExperimental(true); } } - if (vs.hasUserData("cs")) - CodeSystemUtilities.markStatus((CodeSystem) vs.getUserData("cs"), wg, status, pckage, fmm, normativeVersion); + if (vs.hasUserData(UserDataNames.TX_ASSOCIATED_CODESYSTEM)) + CodeSystemUtilities.markStatus((CodeSystem) vs.getUserData(UserDataNames.TX_ASSOCIATED_CODESYSTEM), wg, status, pckage, fmm, normativeVersion); else if (status == StandardsStatus.NORMATIVE && context != null) { for (ConceptSetComponent csc : vs.getCompose().getInclude()) { if (csc.hasSystem()) { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/client/TerminologyClientManager.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/client/TerminologyClientManager.java index 6ca4050f0..345044665 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/client/TerminologyClientManager.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/client/TerminologyClientManager.java @@ -31,6 +31,7 @@ import org.hl7.fhir.r5.terminologies.utilities.TerminologyCache; import org.hl7.fhir.r5.terminologies.utilities.TerminologyCache.SourcedCodeSystem; import org.hl7.fhir.r5.terminologies.utilities.TerminologyCache.SourcedValueSet; import org.hl7.fhir.r5.utils.ToolingExtensions; +import org.hl7.fhir.r5.utils.UserDataNames; import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; import org.hl7.fhir.utilities.ToolingClientLogger; import org.hl7.fhir.utilities.Utilities; @@ -241,8 +242,8 @@ public class TerminologyClientManager { // no agreement? Then what we do depends if (vs != null) { - if (vs.hasUserData("External.Link")) { - String el = vs.getUserString("External.Link"); + if (vs.hasUserData(UserDataNames.render_external_link)) { + String el = vs.getUserString(UserDataNames.render_external_link); if ("https://vsac.nlm.nih.gov".equals(el)) { el = getMaster().getAddress(); } 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 82fd94efd..c83e8e046 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 @@ -125,6 +125,7 @@ import org.hl7.fhir.r5.terminologies.utilities.TerminologyOperationContext.Termi import org.hl7.fhir.r5.terminologies.utilities.TerminologyServiceErrorClass; import org.hl7.fhir.r5.terminologies.utilities.ValueSetProcessBase; import org.hl7.fhir.r5.utils.ToolingExtensions; +import org.hl7.fhir.r5.utils.UserDataNames; import org.hl7.fhir.r5.utils.client.EFhirClientException; import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; import org.hl7.fhir.utilities.Utilities; @@ -1022,8 +1023,8 @@ public class ValueSetExpander extends ValueSetProcessBase { if (ValueSetUtilities.isServerSide(inc.getSystem()) || (cs == null || (cs.getContent() != CodeSystemContentMode.COMPLETE && cs.getContent() != CodeSystemContentMode.FRAGMENT))) { doServerIncludeCodes(inc, heirarchical, exp, imports, expParams, extensions, noInactive, valueSet.getExpansion().getProperty()); } else { - if (cs.hasUserData("supplements.installed")) { - for (String s : cs.getUserString("supplements.installed").split("\\,")) { + if (cs.hasUserData(UserDataNames.tx_known_supplements)) { + for (String s : cs.getUserString(UserDataNames.tx_known_supplements).split("\\,")) { requiredSupplements.remove(s); } } @@ -1090,8 +1091,8 @@ public class ValueSetExpander extends ValueSetProcessBase { UriType u = new UriType(cs.getUrl() + (cs.hasVersion() ? "|"+cs.getVersion() : "")); if (!existsInParams(exp.getParameter(), "used-codesystem", u)) exp.getParameter().add(new ValueSetExpansionParameterComponent().setName("used-codesystem").setValue(u)); - if (cs.hasUserData("supplements.installed")) { - for (String s : cs.getUserString("supplements.installed").split("\\,")) { + if (cs.hasUserData(UserDataNames.tx_known_supplements)) { + for (String s : cs.getUserString(UserDataNames.tx_known_supplements).split("\\,")) { u = new UriType(s); if (!existsInParams(exp.getParameter(), "used-supplement", u)) { exp.getParameter().add(new ValueSetExpansionParameterComponent().setName("used-supplement").setValue(u)); 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 406127929..063d0e1a9 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 @@ -18,6 +18,7 @@ import org.hl7.fhir.r5.model.UrlType; import org.hl7.fhir.r5.model.ValueSet; import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionComponent; import org.hl7.fhir.r5.utils.ToolingExtensions; +import org.hl7.fhir.r5.utils.UserDataNames; import org.hl7.fhir.utilities.StandardsStatus; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.i18n.I18nConstants; @@ -181,8 +182,8 @@ public class ValueSetProcessBase { List iss = makeIssue(IssueSeverity.INFORMATION, IssueType.BUSINESSRULE, null, context.formatMessage(msg, resource.getVersionedUrl(), null, resource.fhirType()), OpIssueCode.StatusCheck, null); // this is a testing hack - see TerminologyServiceTests - iss.get(0).setUserData("status-msg-name", "warning-"+id); - iss.get(0).setUserData("status-msg-value", new UriType(resource.getVersionedUrl())); + iss.get(0).setUserData(UserDataNames.tx_status_msg_name, "warning-"+id); + iss.get(0).setUserData(UserDataNames.tx_status_msg_value, new UriType(resource.getVersionedUrl())); ToolingExtensions.setStringExtension(iss.get(0), ToolingExtensions.EXT_ISSUE_MSG_ID, msg); return iss; 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 44e55cbc8..b306e7ee0 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 @@ -92,6 +92,7 @@ import org.hl7.fhir.r5.terminologies.utilities.ValidationResult; import org.hl7.fhir.r5.terminologies.utilities.ValueSetProcessBase; import org.hl7.fhir.r5.utils.OperationOutcomeUtilities; import org.hl7.fhir.r5.utils.ToolingExtensions; +import org.hl7.fhir.r5.utils.UserDataNames; import org.hl7.fhir.r5.utils.validation.ValidationContextCarrier; import org.hl7.fhir.r5.utils.validation.ValidationContextCarrier.ValidationContextResourceProxy; import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; @@ -240,8 +241,8 @@ public class ValueSetValidator extends ValueSetProcessBase { if (!options.isMembershipOnly()) { int i = 0; for (Coding c : code.getCoding()) { - if (!c.hasSystem() && !c.hasUserData("val.sys.error")) { - c.setUserData("val.sys.error", true); + if (!c.hasSystem() && !c.hasUserData(UserDataNames.tx_val_sys_error)) { + c.setUserData(UserDataNames.tx_val_sys_error, true); info.addIssue(makeIssue(IssueSeverity.WARNING, IssueType.INVALID, path+".coding["+i+"]", context.formatMessage(I18nConstants.CODING_HAS_NO_SYSTEM__CANNOT_VALIDATE), OpIssueCode.InvalidData, null)); } else { VersionInfo vi = new VersionInfo(this); @@ -278,7 +279,7 @@ public class ValueSetValidator extends ValueSetProcessBase { } } } else { - c.setUserData("cs", cs); + c.setUserData(UserDataNames.TX_ASSOCIATED_CODESYSTEM, cs); checkCanonical(info.getIssues(), path, cs, valueset); res = validateCode(path+".coding["+i+"]", c, cs, vcc, info); @@ -361,7 +362,7 @@ public class ValueSetValidator extends ValueSetProcessBase { cd.setDisplay(lookupDisplay(foundCoding)); res.setDefinition(cd); res.setSystem(foundCoding.getSystem()); - res.setVersion(foundCoding.hasVersion() ? foundCoding.getVersion() : foundCoding.hasUserData("cs") ? ((CodeSystem) foundCoding.getUserData("cs")).getVersion() : null); + res.setVersion(foundCoding.hasVersion() ? foundCoding.getVersion() : foundCoding.hasUserData(UserDataNames.TX_ASSOCIATED_CODESYSTEM) ? ((CodeSystem) foundCoding.getUserData(UserDataNames.TX_ASSOCIATED_CODESYSTEM)).getVersion() : null); res.setDisplay(cd.getDisplay()); } if (info.getErr() != null) { @@ -463,8 +464,8 @@ public class ValueSetValidator extends ValueSetProcessBase { private String getVersion(Coding c) { if (c.hasVersion()) { return c.getVersion(); - } else if (c.hasUserData("cs")) { - return ((CodeSystem) c.getUserData("cs")).getVersion(); + } else if (c.hasUserData(UserDataNames.TX_ASSOCIATED_CODESYSTEM)) { + return ((CodeSystem) c.getUserData(UserDataNames.TX_ASSOCIATED_CODESYSTEM)).getVersion(); } else { return null; } @@ -562,8 +563,8 @@ public class ValueSetValidator extends ValueSetProcessBase { } if (!code.hasSystem()) { res = new ValidationResult(IssueSeverity.WARNING, context.formatMessage(I18nConstants.CODING_HAS_NO_SYSTEM__CANNOT_VALIDATE), null); - if (!code.hasUserData("val.sys.error")) { - code.setUserData("val.sys.error", true); + if (!code.hasUserData(UserDataNames.tx_val_sys_error)) { + code.setUserData(UserDataNames.tx_val_sys_error, true); res.getIssues().addAll(makeIssue(IssueSeverity.WARNING, IssueType.INVALID, path, context.formatMessage(I18nConstants.CODING_HAS_NO_SYSTEM__CANNOT_VALIDATE), OpIssueCode.InvalidData, null)); } } else { @@ -831,7 +832,7 @@ public class ValueSetValidator extends ValueSetProcessBase { if ("urn:ietf:rfc:3986".equals(system)) { CodeSystem cs = new CodeSystem(); cs.setUrl(system); - cs.setUserData("tx.cs.special", new URICodeSystem()); + cs.setUserData(UserDataNames.tx_cs_special, new URICodeSystem()); cs.setContent(CodeSystemContentMode.COMPLETE); return cs; } @@ -886,7 +887,7 @@ public class ValueSetValidator extends ValueSetProcessBase { } private ValidationResult validateCode(String path, Coding code, CodeSystem cs, CodeableConcept vcc, ValidationProcessInfo info) { - ConceptDefinitionComponent cc = cs.hasUserData("tx.cs.special") ? ((SpecialCodeSystem) cs.getUserData("tx.cs.special")).findConcept(code) : findCodeInConcept(cs.getConcept(), code.getCode(), cs.getCaseSensitive(), allAltCodes); + ConceptDefinitionComponent cc = cs.hasUserData(UserDataNames.tx_cs_special) ? ((SpecialCodeSystem) cs.getUserData(UserDataNames.tx_cs_special)).findConcept(code) : findCodeInConcept(cs.getConcept(), code.getCode(), cs.getCaseSensitive(), allAltCodes); if (cc == null) { cc = findSpecialConcept(code, cs); } @@ -1592,8 +1593,8 @@ public class ValueSetValidator extends ValueSetProcessBase { public boolean validateCodeInConceptList(String code, CodeSystem def, List list, AlternateCodesProcessingRules altCodeRules) { opContext.deadCheck("validateCodeInConceptList"); - if (def.hasUserData("tx.cs.special")) { - return ((SpecialCodeSystem) def.getUserData("tx.cs.special")).findConcept(new Coding().setCode(code)) != null; + if (def.hasUserData(UserDataNames.tx_cs_special)) { + return ((SpecialCodeSystem) def.getUserData(UserDataNames.tx_cs_special)).findConcept(new Coding().setCode(code)) != null; } else if (def.getCaseSensitive()) { for (ConceptDefinitionComponent cc : list) { if (cc.getCode().equals(code)) { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/OperationOutcomeUtilities.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/OperationOutcomeUtilities.java index 2c11306b6..1a145dd1b 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/OperationOutcomeUtilities.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/OperationOutcomeUtilities.java @@ -52,7 +52,7 @@ public class OperationOutcomeUtilities { public static OperationOutcomeIssueComponent convertToIssue(ValidationMessage message, OperationOutcome op) { OperationOutcomeIssueComponent issue = new OperationOutcome.OperationOutcomeIssueComponent(); - issue.setUserData("source.vm", message); + issue.setUserData(UserDataNames.validator_source_vm, message); issue.setCode(convert(message.getType())); if (message.getLocation() != null) { @@ -76,7 +76,7 @@ public class OperationOutcomeUtilities { if (message.getMessageId() != null) { issue.getExtension().add(ToolingExtensions.makeIssueMessageId(message.getMessageId())); } - issue.setUserData("source.msg", message); + issue.setUserData(UserDataNames.validator_source_msg, message); return issue; } @@ -152,7 +152,7 @@ public class OperationOutcomeUtilities { public static OperationOutcomeIssueComponent convertToIssueSimple(ValidationMessage message, OperationOutcome op) { OperationOutcomeIssueComponent issue = new OperationOutcome.OperationOutcomeIssueComponent(); - issue.setUserData("source.vm", message); + issue.setUserData(UserDataNames.validator_source_vm, message); issue.setCode(convert(message.getType())); if (message.getLocation() != 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 376afc72b..d3ded6922 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 @@ -97,12 +97,14 @@ public class PackageHackerR5 { StructureDefinition sd = (StructureDefinition) r.getResource(); for (ElementDefinition ed : sd.getSnapshot().getElement()) { if (ed.getType().removeIf(tr -> Utilities.existsInList(tr.getCode(), "integer64", "CodeableReference", "RatioRange", "Availability", "ExtendedContactDetail"))) { - sd.setUserData("fixed-by-loader", true); + // sd.setUserData(UserDataNames.fixed_by_loader, true); + // don't need to track this (for now) } } for (ElementDefinition ed : sd.getDifferential().getElement()) { if (ed.getType().removeIf(tr -> Utilities.existsInList(tr.getCode(), "integer64", "CodeableReference", "RatioRange", "Availability", "ExtendedContactDetail"))) { - sd.setUserData("fixed-by-loader", true); + // sd.setUserData(UserDataNames.fixed_by_loader, true); + // don't need to track this (for now) } } } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/QuestionnaireBuilder.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/QuestionnaireBuilder.java index 29ecaf4f3..04c717af3 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/QuestionnaireBuilder.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/QuestionnaireBuilder.java @@ -249,7 +249,7 @@ public class QuestionnaireBuilder { QuestionnaireResponse.QuestionnaireResponseItemComponent item = new QuestionnaireResponse.QuestionnaireResponseItemComponent(); response.addItem(item); item.setLinkId("meta"); - item.setUserData("object", resource); + item.setUserData(UserDataNames.questionnaire_object, resource); } } @@ -353,12 +353,12 @@ public class QuestionnaireBuilder { private void processExisting(String path, List answerGroups, QuestionnaireItemComponent item, List nResponse) throws FHIRException { // processing existing data for (QuestionnaireResponse.QuestionnaireResponseItemComponent ag : answerGroups) { - List children = ((Element) ag.getUserData("object")).listChildrenByName(tail(path)); + List children = ((Element) ag.getUserData(UserDataNames.questionnaire_object)).listChildrenByName(tail(path)); for (Base child : children) { if (child != null) { QuestionnaireResponse.QuestionnaireResponseItemComponent ans = ag.addItem(); ag.setLinkId(item.getLinkId()); - ans.setUserData("object", child); + ans.setUserData(UserDataNames.questionnaire_object, child); nResponse.add(ans); } } @@ -393,13 +393,13 @@ public class QuestionnaireBuilder { for (TypeRefComponent t : types) { Questionnaire.QuestionnaireItemComponent sub = q.addItem(); sub.setType(QuestionnaireItemType.GROUP); - sub.setLinkId(element.getPath()+"._"+t.getUserData("text")); - sub.setText((String) t.getUserData("text")); + sub.setLinkId(element.getPath()+"._"+t.getUserData(UserDataNames.questionnaire_text)); + sub.setText((String) t.getUserData(UserDataNames.questionnaire_text)); // always optional, never repeats List selected = new ArrayList(); selectTypes(profile, sub, t, answerGroups, selected); - processDataType(profile, sub, element, element.getPath()+"._"+t.getUserData("text"), t, selected, parents); + processDataType(profile, sub, element, element.getPath()+"._"+t.getUserData(UserDataNames.questionnaire_text), t, selected, parents); } } else // now we have to build the question panel for each different data type @@ -483,7 +483,7 @@ public class QuestionnaireBuilder { List temp = new ArrayList(); for (QuestionnaireResponse.QuestionnaireResponseItemComponent g : source) - if (instanceOf(t, (Element) g.getUserData("object"))) + if (instanceOf(t, (Element) g.getUserData(UserDataNames.questionnaire_object))) temp.add(g); for (QuestionnaireResponse.QuestionnaireResponseItemComponent g : temp) source.remove(g); @@ -526,7 +526,7 @@ public class QuestionnaireBuilder { dest.add(subg); subg.setLinkId(sub.getLinkId()); subg.setText(sub.getText()); - subg.setUserData("object", g.getUserData("object")); + subg.setUserData(UserDataNames.questionnaire_object, g.getUserData(UserDataNames.questionnaire_object)); } } @@ -590,7 +590,7 @@ public class QuestionnaireBuilder { List children = new ArrayList(); QuestionnaireResponse.QuestionnaireResponseItemComponent aq = null; - Element obj = (Element) ag.getUserData("object"); + Element obj = (Element) ag.getUserData(UserDataNames.questionnaire_object); if (isPrimitive((TypeRefComponent) obj)) children.add(obj); else if (obj instanceof Enumeration) { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/UserDataNames.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/UserDataNames.java new file mode 100644 index 000000000..2378f0983 --- /dev/null +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/UserDataNames.java @@ -0,0 +1,133 @@ +package org.hl7.fhir.r5.utils; + +public class UserDataNames { + public static final String loader_urls_patched = "old.load.mode"; + public static final String loader_custom_resource = "loader-custom-resource"; + + public static final String SNAPSHOT_BASE_MODEL = "base.model"; + public static final String SNAPSHOT_BASE_PATH = "base.path"; + public static final String SNAPSHOT_DERIVATION_EQUALS = "derivation.equals"; + public static final String SNAPSHOT_DERIVATION_POINTER = "derived.pointer"; + public static final String SNAPSHOT_IS_DERIVED = "derived.fact"; + public static final String SNAPSHOT_GENERATED_IN_SNAPSHOT = "profileutilities.snapshot.processed"; + public static final String SNAPSHOT_GENERATING = "profileutils.snapshot.generating"; + public static final String SNAPSHOT_GENERATED = "profileutils.snapshot.generated"; + public static final String SNAPSHOT_GENERATED_MESSAGES = "profileutils.snapshot.generated.messages"; + public static final String SNAPSHOT_ERRORS = "profileutils.snapshot.errors"; + public static final String SNAPSHOT_auto_added_slicing = "auto-added-slicing"; + public static final String SNAPSHOT_messages = "profileutils.snapshot.messages"; + public static final String SNAPSHOT_slice_name = "slice-name"; + public static final String SNAPSHOT_SORT_ed_index = "ed.index"; + public static final String SNAPSHOT_diff_source = "diff-source"; + public static final String SNAPSHOT_regeneration_tracker = "hack.regnerated"; + + public static final String LANGUTILS_ORPHAN = "translations.orphans"; + public static final String LANGUTILS_SOURCE_SUPPLEMENT = "translations.supplemented"; + public static final String LANGUTILS_SOURCE_TRANSLATIONS = "translations.source-list"; + + public static final String rendering_xml_decorations = "fhir_decorations"; + public static final String render_extension_slice = "slice"; + public static final String render_opaque = "render.opaque"; + public static final String render_tx_value = "tx.value"; + public static final String render_tx_pattern = "tx.pattern"; + public static final String render_link = "render.link"; + public static final String render_external_link = "External.Link"; + public static final String render_dict_generator_anchors = "dict.generator.anchors"; + public static final String render_presentation = "presentation"; + public static final String render_src_package = "package"; + public static final String renderer_is_generated = "renderer.generated"; + + public static final String keyview_elementSupported = "elementSupported"; + public static final String keyview_hasFixed = "hasFixed"; + public static final String keyview_usesMustSupport = "usesMustSupport"; + + public static final String LAYOUT_SvgLeft = "SvgLeft"; + public static final String LAYOUT_SvgTop = "SvgTop"; + public static final String LAYOUT_SvgWidth = "SvgWidth"; + public static final String LAYOUT_UmlBreak = "UmlBreak"; + public static final String LAYOUT_UmlDir = "UmlDir"; + + public static final String questionnaire_object = "object"; + public static final String questionnaire_text = "text"; + public static final String mappings_inherited = "private-marked-as-derived"; + + @Deprecated + public static final String deprecated_committee = "committee"; + @Deprecated + public static final String render_filename = "filename"; + public static final String render_webroot = "webroot"; + + public static final String comparison_match = "match"; + public static final String COMP_VERSION_ANNOTATION = "version-annotation"; + public static final String COMP_CONTEXT = "ctxt"; //! + + public static final String tx_status_msg_name = "status-msg-name"; + public static final String tx_status_msg_value = "status-msg-value"; + public static final String tx_val_sys_error = "val.sys.error"; + public static final String tx_cs_special = "tx.cs.special"; + public static final String TX_REQUEST = "source"; + public static final String TX_ASSOCIATED_CODESYSTEM = "cs"; + public static final String tx_cs_version_notes = "cs.version.notes"; + public static final String tx_known_supplements = "supplements.installed"; + + public static final String validator_bundle_resolution = "validator.bundle.resolution"; + public static final String validator_bundle_resolved = "validator.bundle.resolved"; + public static final String validator_expression_cache = "validator.expression.cache"; + public static final String validator_slice_expression_cache = "slice.expression.cache"; + public static final String validator_entry_map = "validator.entrymap"; + public static final String validator_entry_map_reverse = "validator.entrymapR"; + public static final String validation_bundle_error = "bundle.error.noted"; + + public static final String map_profile = "profile"; + public static final String map_validated = "structuremap.validated"; + public static final String map_parameters = "structuremap.parameters"; + public static final String map_source = "element.source"; + public static final String MAP_slice_name = "map-slice-name"; + + public static final String Storage_key = "Storage.key"; + public static final String db_key = "db.key"; + public static final String db_columns = "columns"; + public static final String db_column = "column"; + public static final String db_forEach = "forEach"; + public static final String db_forEachOrNull = "forEachOrNull"; + public static final String db_path = "path"; + public static final String db_name = "name"; + public static final String db_value = "value"; + + public static final String xver_rows = "rows"; + public static final String xver_links = "links"; + public static final String xver_sed = "sed"; + public static final String xver_desc = "desc"; + public static final String xver_cm_used = "cm.used"; + public static final String xver_sliceName = "sliceName"; + public static final String xver_delete = "delete"; + public static final String xver_abstract = "abstract"; + public static final String xver_expression = "expression"; + + + public static final String java_code = "java.code"; + + public static final String validator_source_msg = "source.msg"; + public static final String validator_source_vm = "source.vm"; + + + public static final String PUB_CS_CONVERTED = "conv-vs"; + public static final String pub_xref_used = "xref.used"; + public static final String pub_xref_sources = "xref.sources"; + public static final String pub_resource_config = "config"; + public static final String pub_excel_inv_context = "context"; + public static final String pub_excel_sheet_id = "id"; + public static final String pub_element = "element"; + public static final String pub_loaded_resource = "loaded.resource"; + public static final String pub_source_filename = "source.filename"; + public static final String pub_imposes_compare_id = "imposes.compare.id"; + public static final String pub_analysis = "analysis"; + public static final String pub_logical = "logical"; + public static final String pub_context_file = "igpub.context.file"; + public static final String pub_context_resource = "igpub.context.resource"; + public static final String pub_no_load_deps = "no-load-deps"; + + public static final String kindling_ballot_package = "ballot.package"; + + +} diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/sql/Runner.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/sql/Runner.java index cac93e285..8e4b6c630 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/sql/Runner.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/sql/Runner.java @@ -23,6 +23,7 @@ import org.hl7.fhir.r5.model.IntegerType; import org.hl7.fhir.r5.model.Property; import org.hl7.fhir.r5.model.StringType; import org.hl7.fhir.r5.model.ValueSet; +import org.hl7.fhir.r5.utils.UserDataNames; import org.hl7.fhir.utilities.json.model.JsonObject; import org.hl7.fhir.utilities.validation.ValidationMessage; @@ -150,7 +151,7 @@ public class Runner implements IEvaluationContext { validator.dump(); validator.check(); resourceName = validator.getResourceName(); - wc.store = storage.createStore(wc.vd.asString("name"), (List) wc.vd.getUserData("columns")); + wc.store = storage.createStore(wc.vd.asString("name"), (List) wc.vd.getUserData(UserDataNames.db_columns)); return wc; } @@ -200,7 +201,7 @@ public class Runner implements IEvaluationContext { focus.addAll(executeForEachOrNull(vd, select, b)); if (focus.isEmpty()) { - List columns = (List) select.getUserData("columns"); + List columns = (List) select.getUserData(UserDataNames.db_columns); for (List row : rows) { for (Column c : columns) { Cell cell = cell(row, c.getName()); @@ -272,26 +273,26 @@ public class Runner implements IEvaluationContext { } private List executeForEach(JsonObject vd, JsonObject focus, Base b) { - ExpressionNode n = (ExpressionNode) focus.getUserData("forEach"); + ExpressionNode n = (ExpressionNode) focus.getUserData(UserDataNames.db_forEach); List result = new ArrayList<>(); result.addAll(fpe.evaluate(vd, b, n)); return result; } private List executeForEachOrNull(JsonObject vd, JsonObject focus, Base b) { - ExpressionNode n = (ExpressionNode) focus.getUserData("forEachOrNull"); + ExpressionNode n = (ExpressionNode) focus.getUserData(UserDataNames.db_forEachOrNull); List result = new ArrayList<>(); result.addAll(fpe.evaluate(vd, b, n)); return result; } private void executeColumn(JsonObject vd, JsonObject column, Base b, List> rows) { - ExpressionNode n = (ExpressionNode) column.getUserData("path"); + ExpressionNode n = (ExpressionNode) column.getUserData(UserDataNames.db_path); List bl2 = new ArrayList<>(); if (b != null) { bl2.addAll(fpe.evaluate(vd, b, n)); } - Column col = (Column) column.getUserData("column"); + Column col = (Column) column.getUserData(UserDataNames.db_column); if (col == null) { System.out.println("Error"); } else { @@ -416,7 +417,7 @@ public class Runner implements IEvaluationContext { JsonObject vd = (JsonObject) appContext; JsonObject constant = findConstant(vd, name); if (constant != null) { - Base b = (Base) constant.getUserData("value"); + Base b = (Base) constant.getUserData(UserDataNames.db_value); if (b != null) { list.add(b); } @@ -431,7 +432,7 @@ public class Runner implements IEvaluationContext { JsonObject vd = (JsonObject) appContext; JsonObject constant = findConstant(vd, name.substring(1)); if (constant != null) { - Base b = (Base) constant.getUserData("value"); + Base b = (Base) constant.getUserData(UserDataNames.db_value); if (b != null) { return new TypeDetails(CollectionStatus.SINGLETON, b.fhirType()); } @@ -483,15 +484,15 @@ public class Runner implements IEvaluationContext { List base = new ArrayList(); if (focus.size() == 1) { Base res = focus.get(0); - if (!res.hasUserData("Storage.key")) { + if (!res.hasUserData(UserDataNames.Storage_key)) { String key = storage.getKeyForSourceResource(res); if (key == null) { throw new FHIRException("Unidentified resource: "+res.fhirType()+"/"+res.getIdBase()); } else { - res.setUserData("Storage.key", key); + res.setUserData(UserDataNames.Storage_key, key); } } - base.add(new StringType(res.getUserString("Storage.key"))); + base.add(new StringType(res.getUserString(UserDataNames.Storage_key))); } return base; } @@ -518,15 +519,15 @@ public class Runner implements IEvaluationContext { if (ref != null) { Base target = provider.resolveReference(rootResource, ref, rt); if (target != null) { - if (!res.hasUserData("Storage.key")) { + if (!res.hasUserData(UserDataNames.Storage_key)) { String key = storage.getKeyForTargetResource(target); if (key == null) { throw new FHIRException("Unidentified resource: "+res.fhirType()+"/"+res.getIdBase()); } else { - res.setUserData("Storage.key", key); + res.setUserData(UserDataNames.Storage_key, key); } } - base.add(new StringType(res.getUserString("Storage.key"))); + base.add(new StringType(res.getUserString(UserDataNames.Storage_key))); } } } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/sql/Validator.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/sql/Validator.java index e311be44a..c15c7dbf9 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/sql/Validator.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/sql/Validator.java @@ -34,6 +34,7 @@ import org.hl7.fhir.r5.model.UnsignedIntType; import org.hl7.fhir.r5.model.UriType; import org.hl7.fhir.r5.model.UrlType; import org.hl7.fhir.r5.model.UuidType; +import org.hl7.fhir.r5.utils.UserDataNames; import org.hl7.fhir.r5.utils.sql.Validator.TrueFalseOrUnknown; import org.hl7.fhir.r5.fhirpath.ExpressionNode.CollectionStatus; import org.hl7.fhir.r5.fhirpath.FHIRPathEngine.IssueMessage; @@ -50,6 +51,8 @@ import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType; import org.hl7.fhir.utilities.validation.ValidationMessage.Source; +// see also org.hl7.fhir.validation.instance.type.ViewDefinitionValidator + public class Validator { public enum TrueFalseOrUnknown { @@ -105,7 +108,7 @@ public class Validator { } List columns = new ArrayList<>(); - viewDefinition.setUserData("columns", columns); + viewDefinition.setUserData(UserDataNames.db_columns, columns); JsonElement resourceNameJ = viewDefinition.get("resource"); if (resourceNameJ == null) { @@ -149,7 +152,7 @@ public class Validator { private List checkSelect(JsonObject vd, String path, JsonObject select, TypeDetails t) { List columns = new ArrayList<>(); - select.setUserData("columns", columns); + select.setUserData(UserDataNames.db_columns, columns); checkProperties(select, path, "column", "select", "forEach", "forEachOrNull", "unionAll"); if (select.has("forEach")) { @@ -246,7 +249,7 @@ public class Validator { error(path+".unionAll["+i+"]", ((JsonArray) a).get(ic), "unionAll["+i+"] column definitions do not match: "+diff, IssueType.INVALID); } } - a.setUserData("colunms", columns); + a.setUserData(UserDataNames.db_columns, columns); return columns; } } @@ -287,7 +290,7 @@ public class Validator { ExpressionNode node = null; try { node = fpe.parse(expr); - column.setUserData("path", node); + column.setUserData(UserDataNames.db_path, node); td = fpe.checkOnTypes(vd, resourceName, t, node, warnings); } catch (Exception e) { error(path, expression, e.getMessage(), IssueType.INVALID); @@ -323,7 +326,7 @@ public class Validator { } // ok, name is sorted! if (columnName != null) { - column.setUserData("name", columnName); + column.setUserData(UserDataNames.db_name, columnName); boolean isColl = false; if (column.has("collection")) { JsonElement collectionJ = column.get("collection"); @@ -396,7 +399,7 @@ public class Validator { } if (ok) { Column col = new Column(columnName, isColl, type, kindForType(type)); - column.setUserData("column", col); + column.setUserData(UserDataNames.db_column, col); return col; } } @@ -469,7 +472,7 @@ public class Validator { TypeDetails td = null; try { ExpressionNode n = fpe.parse(expr); - focus.setUserData("forEach", n); + focus.setUserData(UserDataNames.db_forEach, n); td = fpe.checkOnTypes(vd, resourceName, t, n, warnings); } catch (Exception e) { error(path, expression, e.getMessage(), IssueType.INVALID); @@ -494,7 +497,7 @@ public class Validator { TypeDetails td = null; try { ExpressionNode n = fpe.parse(expr); - focus.setUserData("forEachOrNull", n); + focus.setUserData(UserDataNames.db_forEachOrNull, n); td = fpe.checkOnTypes(vd, resourceName, t, n, warnings); } catch (Exception e) { error(path, expression, e.getMessage(), IssueType.INVALID); @@ -570,7 +573,7 @@ public class Validator { error(path+"."+name, j, name+" must be a string", IssueType.INVALID); } else { value.setValueAsString(j.asString()); - constant.setUserData("value", value); + constant.setUserData(UserDataNames.db_value, value); } } @@ -580,7 +583,7 @@ public class Validator { error(path+"."+name, j, name+" must be a boolean", IssueType.INVALID); } else { value.setValueAsString(j.asString()); - constant.setUserData("value", value); + constant.setUserData(UserDataNames.db_value, value); } } @@ -590,7 +593,7 @@ public class Validator { error(path+"."+name, j, name+" must be a number", IssueType.INVALID); } else { value.setValueAsString(j.asString()); - constant.setUserData("value", value); + constant.setUserData(UserDataNames.db_value, value); } } @@ -607,7 +610,7 @@ public class Validator { TypeDetails td = null; try { ExpressionNode n = fpe.parse(expr); - where.setUserData("path", n); + where.setUserData(UserDataNames.db_path, n); td = fpe.checkOnTypes(vd, resourceName, types, n, warnings); } catch (Exception e) { error(path, where.get("path"), e.getMessage(), IssueType.INVALID); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/structuremap/StructureMapUtilities.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/structuremap/StructureMapUtilities.java index f22539dd0..775da9db8 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/structuremap/StructureMapUtilities.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/structuremap/StructureMapUtilities.java @@ -70,6 +70,7 @@ import org.hl7.fhir.r5.renderers.TerminologyRenderer; import org.hl7.fhir.r5.terminologies.expansion.ValueSetExpansionOutcome; import org.hl7.fhir.r5.terminologies.utilities.ValidationResult; import org.hl7.fhir.r5.utils.ToolingExtensions; +import org.hl7.fhir.r5.utils.UserDataNames; import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; import org.hl7.fhir.utilities.FhirPublication; import org.hl7.fhir.utilities.Utilities; @@ -1793,8 +1794,8 @@ public class StructureMapUtilities { if (services != null) res = services.createResource(context.getAppInfo(), res, root); } - if (tgt.hasUserData("profile")) - res.setUserData("profile", tgt.getUserData("profile")); + if (tgt.hasUserData(UserDataNames.map_profile)) + res.setUserData(UserDataNames.map_profile, tgt.getUserData(UserDataNames.map_profile)); return res; case COPY: return getParam(vars, tgt.getParameter().get(0)); @@ -2468,7 +2469,7 @@ public class StructureMapUtilities { StructureDefinition sd = var.getProperty().getProfileProperty().getStructure(); ElementDefinition ednew = sd.getDifferential().addElement(); ednew.setPath(var.getProperty().getProfileProperty().getDefinition().getPath() + "." + pc.getName()); - ednew.setUserData("slice-name", sliceName); + ednew.setUserData(UserDataNames.MAP_slice_name, sliceName); // todo.. why do this? ednew.setFixed(fixed); for (ProfiledType pt : type.getProfiledTypes()) { if (pt.hasBindings()) @@ -2620,7 +2621,7 @@ public class StructureMapUtilities { profile.setBaseDefinition(prop.getBaseProperty().getStructure().getUrl()); profile.setName("Profile for " + profile.getType() + " for " + sliceName); profile.setUrl(map.getUrl().replace("StructureMap", "StructureDefinition") + "-" + profile.getType() + suffix); - ctxt.setUserData("profile", profile.getUrl()); // then we can easily assign this profile url for validation later when we actually transform + ctxt.setUserData(UserDataNames.map_profile, profile.getUrl()); // then we can easily assign this profile url for validation later when we actually transform profile.setId(map.getId() + "-" + profile.getType() + suffix); profile.setStatus(map.getStatus()); profile.setExperimental(map.getExperimental()); 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 d3cd56aab..fb0bcf3f7 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 @@ -65,6 +65,7 @@ import org.hl7.fhir.r5.model.Enumerations.PublicationStatus; import org.hl7.fhir.r5.model.OperationOutcome.OperationOutcomeIssueComponent; import org.hl7.fhir.r5.terminologies.ValueSetUtilities; import org.hl7.fhir.r5.utils.ToolingExtensions; +import org.hl7.fhir.r5.utils.UserDataNames; import org.hl7.fhir.r5.utils.XVerExtensionManager; import org.hl7.fhir.r5.utils.XVerExtensionManager.XVerExtensionStatus; import org.hl7.fhir.r5.utils.validation.IMessagingServices; @@ -1022,16 +1023,16 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi protected Element resolveInBundle(Element bundle, List entries, String ref, String fullUrl, String type, String id, NodeStack stack, List errors, String name, Element source, boolean isWarning, boolean isNLLink) { @SuppressWarnings("unchecked") - Map> map = (Map>) bundle.getUserData("validator.entrymap"); + Map> map = (Map>) bundle.getUserData(UserDataNames.validator_entry_map); @SuppressWarnings("unchecked") - Map> relMap = (Map>) bundle.getUserData("validator.entrymapR"); + Map> relMap = (Map>) bundle.getUserData(UserDataNames.validator_entry_map_reverse); List list = null; if (map == null) { map = new HashMap<>(); - bundle.setUserData("validator.entrymap", map); + bundle.setUserData(UserDataNames.validator_entry_map, map); relMap = new HashMap<>(); - bundle.setUserData("validator.entrymapR", relMap); + bundle.setUserData(UserDataNames.validator_entry_map_reverse, relMap); for (Element entry : entries) { String fu = entry.getNamedChildValue(FULL_URL, false); list = map.get(fu); @@ -1075,8 +1076,8 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi String tt = extractResourceType(ref); ok = VersionUtilities.getCanonicalResourceNames(context.getVersion()).contains(tt); } - if (!ok && stack != null && !sessionId.equals(source.getUserString("bundle.error.noted"))) { - source.setUserData("bundle.error.noted", sessionId); + if (!ok && stack != null && !sessionId.equals(source.getUserString(UserDataNames.validation_bundle_error))) { + source.setUserData(UserDataNames.validation_bundle_error, sessionId); hintOrError(!isWarning, errors, NO_RULE_DATE, IssueType.NOTFOUND, stack, false, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOTFOUND, ref, name); } return null; @@ -1084,17 +1085,17 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi if (fragment != null) { int i = countFragmentMatches(el.get(0), fragment); if (i == 0) { - source.setUserData("bundle.error.noted", sessionId); + source.setUserData(UserDataNames.validation_bundle_error, sessionId); hintOrError(isNLLink, errors, NO_RULE_DATE, IssueType.NOTFOUND, stack, false, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOTFOUND_FRAGMENT, ref, fragment, name); } else if (i > 1) { - source.setUserData("bundle.error.noted", sessionId); + source.setUserData(UserDataNames.validation_bundle_error, sessionId); rule(errors, "2023-11-15", IssueType.INVALID, stack, false, I18nConstants.BUNDLE_BUNDLE_ENTRY_FOUND_MULTIPLE_FRAGMENT, i, ref, fragment, name); } } return el.get(0); } else { - if (stack != null && !sessionId.equals(source.getUserString("bundle.error.noted"))) { - source.setUserData("bundle.error.noted", sessionId); + if (stack != null && !sessionId.equals(source.getUserString(UserDataNames.validation_bundle_error))) { + source.setUserData(UserDataNames.validation_bundle_error, sessionId); rule(errors, "2023-11-15", IssueType.INVALID, stack, false, I18nConstants.BUNDLE_BUNDLE_ENTRY_FOUND_MULTIPLE, el.size(), ref, name); } return null; @@ -1110,8 +1111,8 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi if (el.size() == 1) { return el.get(0); } else { - if (stack != null && !sessionId.equals(source.getUserString("bundle.error.noted"))) { - source.setUserData("bundle.error.noted", sessionId); + if (stack != null && !sessionId.equals(source.getUserString(UserDataNames.validation_bundle_error))) { + source.setUserData(UserDataNames.validation_bundle_error, sessionId); rule(errors, "2023-11-15", IssueType.INVALID, stack, false, I18nConstants.BUNDLE_BUNDLE_ENTRY_FOUND_MULTIPLE, el.size(), ref, name); } return null; @@ -1132,17 +1133,17 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi if (!VersionUtilities.isR4Plus(context.getVersion())) { if (el.size() == 1) { return el.get(0); - } else if (stack != null && !sessionId.equals(source.getUserString("bundle.error.noted"))) { - source.setUserData("bundle.error.noted", sessionId); + } else if (stack != null && !sessionId.equals(source.getUserString(UserDataNames.validation_bundle_error))) { + source.setUserData(UserDataNames.validation_bundle_error, sessionId); rulePlural(errors, "2023-11-15", IssueType.INVALID, stack, false, el.size(), I18nConstants.BUNDLE_BUNDLE_ENTRY_NOTFOUND_APPARENT, ref, name, CommaSeparatedStringBuilder.join(",", Utilities.sorted(tl))); } - } else if (stack != null && !sessionId.equals(source.getUserString("bundle.error.noted"))) { - source.setUserData("bundle.error.noted", sessionId); + } else if (stack != null && !sessionId.equals(source.getUserString(UserDataNames.validation_bundle_error))) { + source.setUserData(UserDataNames.validation_bundle_error, sessionId); rulePlural(errors, "2023-11-15", IssueType.INVALID, stack, false, el.size(), I18nConstants.BUNDLE_BUNDLE_ENTRY_NOTFOUND_APPARENT, ref, name, CommaSeparatedStringBuilder.join(",", Utilities.sorted(tl))); } } else { - if (stack != null && !sessionId.equals(source.getUserString("bundle.error.noted"))) { - source.setUserData("bundle.error.noted", sessionId); + if (stack != null && !sessionId.equals(source.getUserString(UserDataNames.validation_bundle_error))) { + source.setUserData(UserDataNames.validation_bundle_error, sessionId); hintOrError(!isWarning, errors, NO_RULE_DATE, IssueType.NOTFOUND, stack, false, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOTFOUND, ref, name); } } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/renderers/DefaultRenderer.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/renderers/DefaultRenderer.java index ff5919a3d..26f870110 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/renderers/DefaultRenderer.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/renderers/DefaultRenderer.java @@ -5,6 +5,7 @@ import java.io.File; import org.hl7.fhir.r5.model.OperationOutcome; import org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity; import org.hl7.fhir.r5.utils.ToolingExtensions; +import org.hl7.fhir.r5.utils.UserDataNames; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.validation.ValidationMessage; @@ -35,7 +36,7 @@ public class DefaultRenderer extends ValidationOutputRenderer { dst.println((error == 0 ? "Success" : "*FAILURE*") + ": " + Integer.toString(error) + " errors, " + Integer.toString(warn) + " warnings, " + Integer.toString(info) + " notes"); for (OperationOutcome.OperationOutcomeIssueComponent issue : oo.getIssue()) { dst.println(getIssueSummary(issue)+renderMessageId(issue)); - ValidationMessage vm = (ValidationMessage) issue.getUserData("source.msg"); + ValidationMessage vm = (ValidationMessage) issue.getUserData(UserDataNames.validator_source_msg); if (vm != null && vm.sliceText != null && (crumbTrails || vm.isCriticalSignpost())) { for (String s : vm.sliceText) { dst.println(" slice info: "+s); diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/StructureDefinitionValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/StructureDefinitionValidator.java index 235a448a8..bbf3af5a9 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/StructureDefinitionValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/StructureDefinitionValidator.java @@ -44,6 +44,7 @@ import org.hl7.fhir.r5.model.ValueSet; import org.hl7.fhir.r5.terminologies.utilities.TerminologyServiceErrorClass; import org.hl7.fhir.r5.terminologies.utilities.ValidationResult; import org.hl7.fhir.r5.utils.ToolingExtensions; +import org.hl7.fhir.r5.utils.UserDataNames; import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; import org.hl7.fhir.utilities.FhirPublication; import org.hl7.fhir.utilities.Utilities; @@ -98,7 +99,7 @@ public class StructureDefinitionValidator extends BaseValidator { ok = rule(errors, "2022-11-02", IssueType.NOTFOUND, stack.getLiteralPath(), bok, I18nConstants.SD_CONSTRAINED_KIND_NO_MATCH, sd.getKind().toCode(), base.getKind().toCode(), base.getType(), base.getUrl()) && ok; if (sd.getDerivation() == TypeDerivationRule.CONSTRAINT) { ok = rule(errors, "2022-11-02", IssueType.NOTFOUND, stack.getLiteralPath(), sd.hasType() && sd.getType().equals(base.getType()), I18nConstants.SD_CONSTRAINED_TYPE_NO_MATCH, sd.getType(), base.getType()) && ok; - if (!src.hasUserData("profileutils.snapshot.errors")) { // if it does, we've already logged these errors elsewhere + if (!src.hasUserData(UserDataNames.SNAPSHOT_ERRORS)) { // if it does, we've already logged these errors elsewhere List msgs = new ArrayList<>(); ProfileUtilities pu = new ProfileUtilities(context, msgs, null); pu.setForPublication(forPublication); diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/StructureMapValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/StructureMapValidator.java index b65fbcbc4..8a9c4b343 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/StructureMapValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/StructureMapValidator.java @@ -29,6 +29,7 @@ import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent; import org.hl7.fhir.r5.terminologies.ConceptMapUtilities; import org.hl7.fhir.r5.terminologies.ValueSetUtilities; import org.hl7.fhir.r5.terminologies.expansion.ValueSetExpansionOutcome; +import org.hl7.fhir.r5.utils.UserDataNames; import org.hl7.fhir.r5.utils.structuremap.ResolvedGroup; import org.hl7.fhir.r5.utils.structuremap.StructureMapUtilities; import org.hl7.fhir.r5.utils.validation.IResourceValidator; @@ -355,9 +356,9 @@ public class StructureMapValidator extends BaseValidator { fired = false; cc = 0; for (Element group : groups) { - if (!group.hasUserData("structuremap.validated")) { - if (hasInputTypes(group) || group.hasUserData("structuremap.parameters")) { - group.setUserData("structuremap.validated", true); + if (!group.hasUserData(UserDataNames.map_validated)) { + if (hasInputTypes(group) || group.hasUserData(UserDataNames.map_parameters)) { + group.setUserData(UserDataNames.map_validated, true); fired = true; ok = validateGroup(valContext, errors, src, group, stack.push(group, cc, null, null), grpNames) && ok; } @@ -368,7 +369,7 @@ public class StructureMapValidator extends BaseValidator { cc = 0; for (Element group : groups) { - if (!group.hasUserData("structuremap.validated")) { + if (!group.hasUserData(UserDataNames.map_validated)) { hint(errors, "2023-03-01", IssueType.INFORMATIONAL, group.line(), group.col(), stack.push(group, cc, null, null).getLiteralPath(), ok, I18nConstants.SM_ORPHAN_GROUP, group.getChildValue("name")); ok = validateGroup(valContext, errors, src, group, stack.push(group, cc, null, null), grpNames) && ok; } @@ -421,7 +422,7 @@ public class StructureMapValidator extends BaseValidator { } VariableSet variables = new VariableSet(); - VariableSet pvars = (VariableSet) group.getUserData("structuremap.parameters"); + VariableSet pvars = (VariableSet) group.getUserData(UserDataNames.map_parameters); // first, load all the inputs List inputs = group.getChildrenByName("input"); @@ -466,7 +467,7 @@ public class StructureMapValidator extends BaseValidator { private StructureMapGroupComponent makeGroupComponent(Element group) { StructureMapGroupComponent grp = new StructureMapGroupComponent(); - grp.setUserData("element.source", group); + grp.setUserData(UserDataNames.map_source, group); grp.setName(group.getChildValue("name")); List inputs = group.getChildrenByName("input"); for (Element input : inputs) { @@ -1274,13 +1275,13 @@ public class StructureMapValidator extends BaseValidator { } cc++; } - if (ok && grp.getTargetGroup().hasUserData("element.source")) { - Element g = (Element) grp.getTargetGroup().getUserData("element.source"); - if (g.hasUserData("structuremap.parameters")) { - VariableSet pvars = (VariableSet) g.getUserData("structuremap.parameters"); + if (ok && grp.getTargetGroup().hasUserData(UserDataNames.map_source)) { + Element g = (Element) grp.getTargetGroup().getUserData(UserDataNames.map_source); + if (g.hasUserData(UserDataNames.map_parameters)) { + VariableSet pvars = (VariableSet) g.getUserData(UserDataNames.map_parameters); warning(errors, "2023-03-01", IssueType.INVALID, dependent.line(), dependent.col(), stack.getLiteralPath(), pvars.matches(lvars), I18nConstants.SM_DEPENDENT_PARAM_TYPE_MISMATCH_DUPLICATE, grp.getTargetGroup().getName(), pvars.summary(), lvars.summary()); } else { - g.setUserData("structuremap.parameters", lvars); + g.setUserData(UserDataNames.map_parameters, lvars); } } } From a5c23e119cb5579edb6f80ccf723c08bc779e4e4 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Thu, 14 Nov 2024 22:50:40 +1030 Subject: [PATCH 02/10] expose User data through ResourceWrapper interface --- .../hl7/fhir/convertors/wrapper/ResourceWrapperR4.java | 5 +++++ .../hl7/fhir/convertors/wrapper/ResourceWrapperR4B.java | 5 +++++ .../org/hl7/fhir/r5/renderers/utils/ResourceWrapper.java | 1 + .../hl7/fhir/r5/renderers/utils/ResourceWrapperModel.java | 5 +++++ .../fhir/r5/renderers/utils/ResourceWrapperNative.java | 8 +++++++- 5 files changed, 23 insertions(+), 1 deletion(-) diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/wrapper/ResourceWrapperR4.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/wrapper/ResourceWrapperR4.java index c766f5010..46c3d8060 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/wrapper/ResourceWrapperR4.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/wrapper/ResourceWrapperR4.java @@ -242,4 +242,9 @@ public class ResourceWrapperR4 extends ResourceWrapper { return null; } + @Override + public boolean hasUserData(String name) { + return element.hasUserData(name); + } + } \ No newline at end of file diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/wrapper/ResourceWrapperR4B.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/wrapper/ResourceWrapperR4B.java index e7e461091..fa60e02d1 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/wrapper/ResourceWrapperR4B.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/wrapper/ResourceWrapperR4B.java @@ -242,4 +242,9 @@ public class ResourceWrapperR4B extends ResourceWrapper { return null; } + @Override + public boolean hasUserData(String name) { + return element.hasUserData(name); + } + } \ No newline at end of file diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/ResourceWrapper.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/ResourceWrapper.java index 5bcf1bc2f..be4ad1c10 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/ResourceWrapper.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/ResourceWrapper.java @@ -522,6 +522,7 @@ public abstract class ResourceWrapper { public abstract boolean hasPrimitiveValue(); public abstract String primitiveValue(); public abstract boolean isResource(); + public abstract boolean hasUserData(String name); } \ No newline at end of file diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/ResourceWrapperModel.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/ResourceWrapperModel.java index ff4c40148..f09abd559 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/ResourceWrapperModel.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/ResourceWrapperModel.java @@ -270,5 +270,10 @@ public class ResourceWrapperModel extends ResourceWrapper { return null; } + @Override + public boolean hasUserData(String name) { + return model.hasUserData(name); + } + } \ No newline at end of file diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/ResourceWrapperNative.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/ResourceWrapperNative.java index cefc9110a..785f3881e 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/ResourceWrapperNative.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/ResourceWrapperNative.java @@ -10,6 +10,7 @@ import org.hl7.fhir.r5.model.Enumeration; import org.hl7.fhir.r5.model.Narrative; import org.hl7.fhir.r5.model.Property; import org.hl7.fhir.r5.model.Resource; +import org.hl7.fhir.r5.utils.UserDataNames; import org.hl7.fhir.utilities.xhtml.NodeType; import org.hl7.fhir.utilities.xhtml.XhtmlNode; @@ -143,7 +144,7 @@ public class ResourceWrapperNative extends ResourceWrapper { public void setNarrative(XhtmlNode x, String status, boolean multiLangMode, Locale locale, boolean isPretty) { if (element instanceof DomainResource) { DomainResource r = (DomainResource) element; - r.getText().setUserData("renderer.generated", true); + r.getText().setUserData(UserDataNames.renderer_is_generated, true); if (!r.hasText() || !r.getText().hasDiv()) { r.setText(new Narrative()); r.getText().setStatusAsString(status); @@ -231,4 +232,9 @@ public class ResourceWrapperNative extends ResourceWrapper { return null; } + @Override + public boolean hasUserData(String name) { + return element.hasUserData(name); + } + } \ No newline at end of file From 356661eef03527be2382d8746f26c9f94331664f Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Thu, 14 Nov 2024 22:51:13 +1030 Subject: [PATCH 03/10] Implementation for ViewDefinition as custom resource --- .../org/hl7/fhir/r5/context/TypeManager.java | 3 +- .../fhir/r5/renderers/RendererFactory.java | 2 +- .../r5/renderers/ViewDefinitionRenderer.java | 69 +++ .../org/hl7/fhir/r5/utils/sql/Column.java | 2 +- .../fhir/utilities/i18n/I18nConstants.java | 16 + .../instance/InstanceValidator.java | 44 +- .../type/ViewDefinitionValidator.java | 405 ++++++++++++++++++ pom.xml | 2 +- 8 files changed, 519 insertions(+), 24 deletions(-) create mode 100644 org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ViewDefinitionRenderer.java create mode 100644 org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ViewDefinitionValidator.java diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/TypeManager.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/TypeManager.java index ed1909ea9..596627b3b 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/TypeManager.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/TypeManager.java @@ -12,6 +12,7 @@ import org.hl7.fhir.r5.context.CanonicalResourceManager.CanonicalResourceProxy; import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind; import org.hl7.fhir.r5.model.StructureDefinition.TypeDerivationRule; +import org.hl7.fhir.r5.utils.UserDataNames; import org.hl7.fhir.utilities.Utilities; public class TypeManager { @@ -55,7 +56,7 @@ public class TypeManager { typeDefinitions.put(type, types); } types.add(sd); - if (sd.getUrl().startsWith("http://hl7.org/fhir/StructureDefinition/")) { + if (sd.getUrl().startsWith("http://hl7.org/fhir/StructureDefinition/") || "true".equals(sd.getUserString(UserDataNames.loader_custom_resource))) { types = fhirTypeDefinitions.get(type); if (types == null) { types = new HashSet<>(); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/RendererFactory.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/RendererFactory.java index 7fd3e98fd..dbba1ef36 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/RendererFactory.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/RendererFactory.java @@ -70,7 +70,7 @@ public class RendererFactory { switch (resource.fhirType()) { case "DiagnosticReport": return new DiagnosticReportRenderer(context); case "Library": return new LibraryRenderer(context); - case "Questionnaire": return new LibraryRenderer(context); + case "ViewDefinition": return new ViewDefinitionRenderer(context); case "List": return new ListRenderer(context); case "Patient": return new PatientRenderer(context); case "Provenance": return new ProvenanceRenderer(context); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ViewDefinitionRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ViewDefinitionRenderer.java new file mode 100644 index 000000000..34678644e --- /dev/null +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ViewDefinitionRenderer.java @@ -0,0 +1,69 @@ +package org.hl7.fhir.r5.renderers; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.util.List; + +import org.apache.commons.codec.binary.Base64; +import org.hl7.fhir.exceptions.DefinitionException; +import org.hl7.fhir.exceptions.FHIRException; +import org.hl7.fhir.exceptions.FHIRFormatError; +import org.hl7.fhir.r5.model.CanonicalResource; +import org.hl7.fhir.r5.model.Resource; +import org.hl7.fhir.r5.renderers.utils.RenderingContext; +import org.hl7.fhir.r5.renderers.utils.ResourceWrapper; +import org.hl7.fhir.r5.utils.EOperationOutcome; +import org.hl7.fhir.r5.utils.UserDataNames; +import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; +import org.hl7.fhir.utilities.Utilities; +import org.hl7.fhir.utilities.VersionUtilities; +import org.hl7.fhir.utilities.xhtml.XhtmlNode; + +public class ViewDefinitionRenderer extends ResourceRenderer { + + public ViewDefinitionRenderer(RenderingContext context) { + super(context); + } + + @Override + public String buildSummary(ResourceWrapper r) throws UnsupportedEncodingException, IOException { + return canonicalTitle(r); + } + + @Override + public void buildNarrative(RenderingStatus status, XhtmlNode x, ResourceWrapper vd) throws FHIRFormatError, DefinitionException, IOException, FHIRException, EOperationOutcome { + renderResourceTechDetails(vd, x); + genSummaryTable(status, x, vd); + + XhtmlNode tbl = x.table("grid"); + + // row 1: identity + XhtmlNode tr = tbl.tr(); + tr.para().tx("This view definition produces a table \""+vd.primitiveValue("name")+"\""); + + // row 2: content + tr = tbl.tr(); + CommaSeparatedStringBuilder cb = new CommaSeparatedStringBuilder(", ", " and "); + for (ResourceWrapper v : vd.children("fhirVersion")) { + String ver = v.primitiveValue(); + cb.append(""+VersionUtilities.getNameForVersion(ver)+""); + } + String vh = cb.count() == 0 ? "" : cb.count() == 1 ? "version " +cb.toString() : "versions "+cb.toString(); + + if (vd.has("resourceProfile")) { + XhtmlNode p = tr.para(); + p.tx("This view acts on "+vh+" "+cb.toString()+" "+vd.primitiveValue("resource")+" using profile ?"); + // todo + } else { + tr.para().tx("This view acts on "+vh+" "+cb.toString()+" "+vd.primitiveValue("resource")); + } + + // row 3: columns + tr = tbl.tr(); + tr.para().tx("This view creates the following columns:"); + // row 4: select tree + tr = tbl.tr(); + tr.para().tx("This view selects the following cells"); + } + +} diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/sql/Column.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/sql/Column.java index 745e5c99d..0fa2f664e 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/sql/Column.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/sql/Column.java @@ -13,7 +13,7 @@ public class Column { super(); } - protected Column(String name, boolean isColl, String type, ColumnKind kind) { + public Column(String name, boolean isColl, String type, ColumnKind kind) { super(); this.name = name; this.isColl = isColl; 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 c36b67897..fb522a7f6 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 @@ -1126,4 +1126,20 @@ public class I18nConstants { public static final String SD_PATH_SLICING_DEPRECATED = "SD_PATH_SLICING_DEPRECATED"; public static final String SD_PATH_NOT_VALID = "SD_PATH_NOT_VALID"; public static final String SD_PATH_ERROR = "SD_PATH_ERROR"; + public static final String VIEWDEFINITION_SHOULD_HAVE_NAME = null; + public static final String VIEWDEFINITION_NAME_INVALID = null; + public static final String VIEWDEFINITION_CONSTANT_NAME_INVALID = null; + public static final String VIEWDEFINITION_PATH_ERROR = null; + public static final String VIEWDEFINITION_PATH_WRONG_RETURN = null; + public static final String VIEWDEFINITION_PATH_WARNING = null; + public static final String VIEWDEFINITION_UNKNOWN_RESOURCE = null; + public static final String VIEWDEFINITION_DUPL_COL_NAME = null; + public static final String VIEWDEFINITION_NAME_ILLEGAL = null; + public static final String VIEWDEFINITION_NAME_REQUIRED = null; + public static final String VIEWDEFINITION_COLLECTION_NOT_NEEDED = null; + public static final String VIEWDEFINITION_COLLECTION_NOT_ALWAYS = null; + public static final String VIEWDEFINITION_COLLECTION_NEEDED = null; + public static final String VIEWDEFINITION_TYPE_MISMATCH = null; + public static final String VIEWDEFINITION_UNABLE_TO_TYPE = null; + public static final String VIEWDEFINITION_COMPLEX_TYPE = null; } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java index e8d0912d7..805ae5226 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 @@ -161,6 +161,7 @@ import org.hl7.fhir.r5.terminologies.utilities.ValidationResult; import org.hl7.fhir.r5.utils.BuildExtensions; import org.hl7.fhir.r5.utils.ResourceUtilities; import org.hl7.fhir.r5.utils.ToolingExtensions; +import org.hl7.fhir.r5.utils.UserDataNames; import org.hl7.fhir.r5.utils.XVerExtensionManager; import org.hl7.fhir.r5.utils.XVerExtensionManager.XVerExtensionStatus; import org.hl7.fhir.r5.utils.sql.Validator; @@ -216,6 +217,7 @@ import org.hl7.fhir.validation.instance.type.StructureMapValidator; import org.hl7.fhir.validation.instance.type.StructureMapValidator.VariableDefn; import org.hl7.fhir.validation.instance.type.StructureMapValidator.VariableSet; import org.hl7.fhir.validation.instance.type.ValueSetValidator; +import org.hl7.fhir.validation.instance.type.ViewDefinitionValidator; import org.hl7.fhir.validation.instance.utils.Base64Util; import org.hl7.fhir.validation.instance.utils.CanonicalResourceLookupResult; import org.hl7.fhir.validation.instance.utils.CanonicalTypeSorter; @@ -442,8 +444,8 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat public Base resolveReference(FHIRPathEngine engine, Object appContext, String url, Base refContext) throws FHIRException { ValidationContext c = (ValidationContext) appContext; - if (refContext != null && refContext.hasUserData("validator.bundle.resolution")) { - return (Base) refContext.getUserData("validator.bundle.resolution"); + if (refContext != null && refContext.hasUserData(UserDataNames.validator_bundle_resolution)) { + return (Base) refContext.getUserData(UserDataNames.validator_bundle_resolution); } if (c.getAppContext() instanceof Element) { @@ -1023,9 +1025,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat || (element.getName().equals("id") && !element.getPath().substring(0, element.getPath().length()-3).contains(".")) || (element.getName().equals("text") && !element.getPath().substring(0, element.getPath().length()-5).contains("."))) return; - String hasFixed = element.getUserString("hasFixed"); + String hasFixed = element.getUserString(UserDataNames.keyview_hasFixed); if (element.getPath().contains(".") && (hasFixed== null || !hasFixed.equals("Y"))) { - String elementUsage = element.getUserString("elementSupported"); + String elementUsage = element.getUserString(UserDataNames.keyview_elementSupported); hint(errors, NO_RULE_DATE, IssueType.INFORMATIONAL, element.line(), element.col(), stack.getLiteralPath(), elementUsage != null && (elementUsage.equals("Y") || elementUsage.equals("NA")), I18nConstants.MUSTSUPPORT_VAL_MUSTSUPPORT, element.getName(), element.getProperty().getStructure().getVersionedUrl()); if (elementUsage==null || !elementUsage.equals("Y")) return; @@ -5112,7 +5114,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (!slicer.getSlicing().hasDiscriminator()) return false; // cannot validate in this case - ExpressionNode n = (ExpressionNode) ed.getUserData("slice.expression.cache"); + ExpressionNode n = (ExpressionNode) ed.getUserData(UserDataNames.validator_slice_expression_cache); if (n == null) { long t = System.nanoTime(); // GG: this approach is flawed because it treats discriminators individually rather than collectively @@ -5230,7 +5232,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat throw new FHIRException(context.formatMessage(I18nConstants.PROBLEM_PROCESSING_EXPRESSION__IN_PROFILE__PATH__, expression, profile.getVersionedUrl(), path, e.getMessage())); } timeTracker.fpe(t); - ed.setUserData("slice.expression.cache", n); + ed.setUserData(UserDataNames.validator_slice_expression_cache, n); } else { } @@ -5780,8 +5782,8 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat // } private void resolveBundleReferences(Element element, List bundles) { - if (!element.hasUserData("validator.bundle.resolved")) { - element.setUserData("validator.bundle.resolved", true); + if (!element.hasUserData(UserDataNames.validator_bundle_resolved)) { + element.setUserData(UserDataNames.validator_bundle_resolved, true); List list = new ArrayList(); list.addAll(bundles); list.add(0, element); @@ -5814,7 +5816,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat List entries = bundle.getChildren(ENTRY); Element tgt = resolveInBundle(bundle, entries, ref, fu, resource.fhirType(), resource.getIdBase(), null, null, null, element, false, false); if (tgt != null) { - element.setUserData("validator.bundle.resolution", tgt.getNamedChild(RESOURCE, false)); + element.setUserData(UserDataNames.validator_bundle_resolution, tgt.getNamedChild(RESOURCE, false)); return; } } @@ -5943,6 +5945,8 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat return new StructureMapValidator(this, fpe, profileUtilities).validateStructureMap(valContext, errors, element, stack) && ok; } else if (element.getType().equals("ValueSet")) { return new ValueSetValidator(this).validateValueSet(valContext, errors, element, stack) && ok; + } else if (element.getType().equals("ViewDefinition")) { + return new ViewDefinitionValidator(this, fpe).validateViewDefinition(valContext, errors, element, stack) && ok; } else if (element.getType().equals("ImplementationGuide")) { return new ImplementationGuideValidator(this.context, xverManager, debug).validateImplementationGuide(valContext, errors, element, stack) && ok; } else if ("http://hl7.org/fhir/uv/sql-on-fhir/StructureDefinition/ViewDefinition".equals(element.getProperty().getStructure().getUrl())) { @@ -6921,7 +6925,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } public void checkMustSupport(StructureDefinition profile, ElementInfo ei) { - String usesMustSupport = profile.getUserString("usesMustSupport"); + String usesMustSupport = profile.getUserString(UserDataNames.keyview_usesMustSupport); if (usesMustSupport == null) { usesMustSupport = "N"; for (ElementDefinition pe : profile.getSnapshot().getElement()) { @@ -6930,18 +6934,18 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat break; } } - profile.setUserData("usesMustSupport", usesMustSupport); + profile.setUserData(UserDataNames.keyview_usesMustSupport, usesMustSupport); } - String elementSupported = ei.getElement().getUserString("elementSupported"); - String fixedValue = ei.getElement().getUserString("hasFixed"); + String elementSupported = ei.getElement().getUserString(UserDataNames.keyview_elementSupported); + String fixedValue = ei.getElement().getUserString(UserDataNames.keyview_hasFixed); if ((elementSupported == null || !elementSupported.equals("Y")) && ei.definition.getMustSupport()) { if (ei.definition.getMustSupport()) { - ei.getElement().setUserData("elementSupported", "Y"); + ei.getElement().setUserData(UserDataNames.keyview_elementSupported, "Y"); } } else if (elementSupported == null && !usesMustSupport.equals("Y")) - ei.getElement().setUserData("elementSupported", "NA"); + ei.getElement().setUserData(UserDataNames.keyview_elementSupported, "NA"); if (fixedValue==null && (ei.definition.hasFixed() || ei.definition.hasPattern())) - ei.getElement().setUserData("hasFixed", "Y"); + ei.getElement().setUserData(UserDataNames.keyview_hasFixed, "Y"); } public boolean checkCardinalities(List errors, StructureDefinition profile, Element element, NodeStack stack, @@ -7352,7 +7356,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if ("dom-3".equals(inv.getKey())) { return true; } - ExpressionNode n = (ExpressionNode) inv.getUserData("validator.expression.cache"); + ExpressionNode n = (ExpressionNode) inv.getUserData(UserDataNames.validator_expression_cache); if (n == null) { long t = System.nanoTime(); try { @@ -7363,7 +7367,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat return false; } timeTracker.fpe(t); - inv.setUserData("validator.expression.cache", n); + inv.setUserData(UserDataNames.validator_expression_cache, n); } valContext.setProfile(profile); @@ -7665,10 +7669,10 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat for (ElementDefinitionConstraintComponent inv : ed.getConstraint()) { if (inv.hasExpression()) { try { - ExpressionNode n = (ExpressionNode) inv.getUserData("validator.expression.cache"); + ExpressionNode n = (ExpressionNode) inv.getUserData(UserDataNames.validator_expression_cache); if (n == null) { n = fpe.parse(FHIRPathExpressionFixer.fixExpr(inv.getExpression(), inv.getKey(), context.getVersion())); - inv.setUserData("validator.expression.cache", n); + inv.setUserData(UserDataNames.validator_expression_cache, n); } fpe.check(null, sd.getKind() == StructureDefinitionKind.RESOURCE ? sd.getType() : "DomainResource", ed.getPath(), n); } catch (Exception e) { diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ViewDefinitionValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ViewDefinitionValidator.java new file mode 100644 index 000000000..7c886f03d --- /dev/null +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ViewDefinitionValidator.java @@ -0,0 +1,405 @@ +package org.hl7.fhir.validation.instance.type; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.hl7.fhir.exceptions.FHIRException; +import org.hl7.fhir.r5.elementmodel.Element; +import org.hl7.fhir.r5.fhirpath.ExpressionNode; +import org.hl7.fhir.r5.fhirpath.ExpressionNode.CollectionStatus; +import org.hl7.fhir.r5.fhirpath.FHIRPathEngine; +import org.hl7.fhir.r5.fhirpath.FHIRPathEngine.IssueMessage; +import org.hl7.fhir.r5.fhirpath.TypeDetails; +import org.hl7.fhir.r5.utils.UserDataNames; +import org.hl7.fhir.r5.utils.sql.Column; +import org.hl7.fhir.r5.utils.sql.ColumnKind; +import org.hl7.fhir.utilities.Utilities; +import org.hl7.fhir.utilities.i18n.I18nConstants; +import org.hl7.fhir.utilities.validation.ValidationMessage; +import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType; +import org.hl7.fhir.validation.BaseValidator; +import org.hl7.fhir.validation.instance.utils.NodeStack; +import org.hl7.fhir.validation.instance.utils.ValidationContext; + +// see also org.hl7.fhir.r5.utils.sql.Validator +public class ViewDefinitionValidator extends BaseValidator { + + + private FHIRPathEngine fpe; + + public ViewDefinitionValidator(BaseValidator parent, FHIRPathEngine fpe) { + super(parent); + this.fpe = fpe; + } + + public boolean validateViewDefinition(ValidationContext hostContext, List errors, Element vd, NodeStack stack) throws FHIRException { + boolean ok = true; + if (warning(errors, "2024-11-14", IssueType.BUSINESSRULE, stack, vd.hasChild("name"), I18nConstants.VIEWDEFINITION_SHOULD_HAVE_NAME)) { + warning(errors, "2024-11-14", IssueType.BUSINESSRULE, stack, isValidName(vd.getNamedChildValue("name")), I18nConstants.VIEWDEFINITION_NAME_INVALID); + } + + List columns = new ArrayList<>(); + vd.setUserData(UserDataNames.db_columns, columns); + + String resourceName = vd.getNamedChildValue("resource"); + if (resourceName != null) { + if (rule(errors, "2024-11-14", IssueType.BUSINESSRULE, stack, context.getResourceNamesAsSet().contains(resourceName), I18nConstants.VIEWDEFINITION_UNKNOWN_RESOURCE)) { + int i = 0; + for (Element constant : vd.getChildren("constant")) { + ok = checkConstant(hostContext, errors, stack.push(constant, i, null, null), constant) && ok; + i++; + } + i = 0; + for (Element where : vd.getChildren("where")) { + ok = checkWhere(hostContext, errors, vd, stack.push(where, i, null, null), where, resourceName) && ok; + i++; + } + TypeDetails t = new TypeDetails(CollectionStatus.SINGLETON, resourceName); + i = 0; + for (Element select : vd.getChildren("select")) { + List cols = new ArrayList(); + ok = checkSelect(hostContext, errors, vd, vd, stack.push(select, i, null, null), select, resourceName, t, cols) && ok; + columns.addAll(cols); + i++; + } + } + } else { + ok = false; + } + + return ok; + } + + private boolean checkSelect(ValidationContext hostContext, List errors, Element vd, Element parent, NodeStack stack, Element select, String resourceName, TypeDetails t, List columns) { + select.setUserData(UserDataNames.db_columns, columns); + boolean ok = true; + + if (select.hasChild("forEach")) { + Element e = select.getNamedChild("forEach"); + t = checkForEach(hostContext, errors, vd, select, stack.push(e, -1, null, null), e, resourceName, t); + } else if (select.hasChild("forEachOrNull")) { + Element e = select.getNamedChild("forEachOrNull"); + t = checkForEachOrNull(hostContext, errors, vd, select, stack.push(e, -1, null, null), e, resourceName, t); + } + + if (t == null) { + ok = false; + } else { + + if (select.hasChildren("column")) { + int i = 0; + for (Element e : select.getChildren("column")) { + ok = checkColumn(hostContext, errors, vd,select, stack.push(e, i, null, null), e, resourceName, t, columns) && ok; + i++; + } + } + + if (select.hasChildren("select")) { + int i = 0; + for (Element e : select.getChildren("select")) { + ok = checkSelect(hostContext, errors, vd, select, stack.push(e, i, null, null), e, resourceName, t, columns) && ok; + i++; + } + } + + if (select.hasChildren("unionAll")) { + int i = 0; + for (Element e : select.getChildren("unionAll")) { + ok = checkUnion(hostContext, errors, vd, parent, stack.push(e, i, null, null), e, resourceName, t, columns) && ok; + i++; + } + } + checkColumnNamesUnique(errors, stack, columns); + } + return ok; + } + + + private void checkColumnNamesUnique(List errors, NodeStack stack, List columns) { + Set names = new HashSet<>(); + for (Column col : columns) { + if (col != null) { + if (!names.contains(col.getName())) { + names.add(col.getName()); + } else if (!col.isDuplicateReported()) { + col.setDuplicateReported(true); + rule(errors, "2024-11-14", IssueType.BUSINESSRULE, stack, false, I18nConstants.VIEWDEFINITION_DUPL_COL_NAME, col.getName()); + } + } + } + } + + private boolean checkUnion(ValidationContext hostContext, List errors, Element vd, Element parent, NodeStack stack, Element unionAll, String resourceName, TypeDetails t, List columns) { + return false; +// List> unionColumns = new ArrayList<>(); +// int i = 0; +// for (JsonElement e : ((JsonArray) a)) { +// if (!(e instanceof JsonObject)) { +// error(path+".unionAll["+i+"]", e, "unionAll["+i+"] is not an object", IssueType.INVALID); +// } else { +// unionColumns.add(checkSelect(vd, path+".unionAll["+i+"]", (JsonObject) e, t)); +// } +// i++; +// } +// if (i < 2) { +// warning(path+".unionAll", a, "unionAll should have more than one item"); +// } +// if (unionColumns.size() > 1) { +// List columns = unionColumns.get(0); +// for (int ic = 1; ic < unionColumns.size(); ic++) { +// String diff = columnDiffs(columns, unionColumns.get(ic)); +// if (diff != null) { +// error(path+".unionAll["+i+"]", ((JsonArray) a).get(ic), "unionAll["+i+"] column definitions do not match: "+diff, IssueType.INVALID); +// } +// } +// a.setUserData(UserDataNames.db_columns, columns); +// return columns; +// } +// } +// return null; + } + + private String columnDiffs(List list1, List list2) { + if (list1.size() == list2.size()) { + for (int i = 0; i < list1.size(); i++) { + if (list1.get(i) == null || list2.get(i) == null) { + return null; // just suppress any addition errors + } + String diff = list1.get(i).diff(list2.get(i)); + if (diff != null) { + return diff+" at #"+i; + } + } + return null; + } else { + return "Column counts differ: "+list1.size()+" vs "+list2.size(); + } + } + + private boolean checkColumn(ValidationContext hostContext, List errors, Element vd, Element parent, NodeStack stack, Element column, String resourceName, TypeDetails t, List columns) { + boolean ok = true; + String expr = column.getNamedChildValue("path"); + + List warnings = new ArrayList<>(); + TypeDetails td = null; + ExpressionNode node = null; + try { + node = fpe.parse(expr); + column.setUserData(UserDataNames.db_path, node); + td = fpe.checkOnTypes(vd, resourceName, t, node, warnings); + } catch (Exception e) { + rule(errors, "2024-11-14", IssueType.EXCEPTION, stack, false, I18nConstants.VIEWDEFINITION_PATH_ERROR, "forEach", e.getMessage()); + ok = false; + } + if (td != null && node != null) { + for (IssueMessage s : warnings) { + warning(errors, "2024-11-14", IssueType.BUSINESSRULE, stack, false, I18nConstants.VIEWDEFINITION_PATH_WARNING, s.getMessage()); + } + String columnName = column.getNamedChildValue("name"); + if (columnName == null) { + List names = node.getDistalNames(); + if (names.size() == 1 && names.get(0) != null) { + columnName = names.get(0); + ok = rule(errors, "2024-11-14", IssueType.INVALID, stack, isValidName(columnName), I18nConstants.VIEWDEFINITION_NAME_ILLEGAL, columnName) && ok; + } else { + ok = false; + rule(errors, "2024-11-14", IssueType.INVALID, stack, false, I18nConstants.VIEWDEFINITION_NAME_REQUIRED); + } + } + if (columnName != null) { + column.setUserData(UserDataNames.db_name, columnName); + boolean isColl = false; + if (column.hasChild("collection")) { + isColl = "true".equals(column.getNamedChildValue("collection")); + } + if (isColl) { + if (td.getCollectionStatus() == CollectionStatus.SINGLETON) { + hint(errors, "2024-11-14", IssueType.INFORMATIONAL, stack, false, I18nConstants.VIEWDEFINITION_COLLECTION_NOT_NEEDED, expr, columnName); + } + hint(errors, "2024-11-14", IssueType.INFORMATIONAL, stack, false, I18nConstants.VIEWDEFINITION_COLLECTION_NOT_ALWAYS, expr, columnName); + } else { + hint(errors, "2024-11-14", IssueType.INFORMATIONAL, stack, td.getCollectionStatus() == CollectionStatus.SINGLETON, I18nConstants.VIEWDEFINITION_COLLECTION_NEEDED, expr, columnName); + } + Set types = new HashSet<>(); + if (node.isNullSet()) { + types.add("null"); + } else { + // ok collection is sorted + for (String type : td.getTypes()) { + types.add(simpleType(type)); + } + + String type = column.getNamedChildValue("type"); + if (td.hasType(type)) { + types.clear(); + types.add(simpleType(type)); + } else { + ok = rule(errors, "2024-11-14", IssueType.INVALID, stack, false, I18nConstants.VIEWDEFINITION_TYPE_MISMATCH) && ok; + } + } + if (types.size() != 1) { + ok = rule(errors, "2024-11-14", IssueType.INVALID, stack, false, I18nConstants.VIEWDEFINITION_UNABLE_TO_TYPE, td.describe()) && ok; + } else { + String type = types.iterator().next(); + boolean tok = false; + if (!isSimpleType(type) && !"null".equals(type)) { + hint(errors, "2024-11-14", IssueType.INFORMATIONAL, stack, false, I18nConstants.VIEWDEFINITION_COMPLEX_TYPE, expr, type); + } else { + tok = true; + } + if (tok) { + Column col = new Column(columnName, isColl, type, kindForType(type)); + column.setUserData(UserDataNames.db_column, col); + columns.add(col); + } else { + ok = false; + } + } + } + } + return ok; + } + + private ColumnKind kindForType(String type) { + switch (type) { + case "null": return ColumnKind.Null; + case "dateTime": return ColumnKind.DateTime; + case "boolean": return ColumnKind.Boolean; + case "integer": return ColumnKind.Integer; + case "decimal": return ColumnKind.Decimal; + case "string": return ColumnKind.String; + case "canonical": return ColumnKind.String; + case "url": return ColumnKind.String; + case "uri": return ColumnKind.String; + case "oid": return ColumnKind.String; + case "uuid": return ColumnKind.String; + case "id": return ColumnKind.String; + case "code": return ColumnKind.String; + case "base64Binary": return ColumnKind.Binary; + case "time": return ColumnKind.Time; + default: return ColumnKind.Complex; + } + } + + private boolean isSimpleType(String type) { + return Utilities.existsInList(type, "dateTime", "boolean", "integer", "decimal", "string", "base64Binary", "id", "code", "date", "time", "canonical"); + } + + private String simpleType(String type) { + type = type.replace("http://hl7.org/fhirpath/System.", "").replace("http://hl7.org/fhir/StructureDefinition/", ""); + if (Utilities.existsInList(type, "date", "dateTime", "instant")) { + return "dateTime"; + } + if (Utilities.existsInList(type, "Boolean", "boolean")) { + return "boolean"; + } + if (Utilities.existsInList(type, "Integer", "integer", "integer64")) { + return "integer"; + } + if (Utilities.existsInList(type, "Decimal", "decimal")) { + return "decimal"; + } + if (Utilities.existsInList(type, "String", "string", "code")) { + return "string"; + } + if (Utilities.existsInList(type, "Time", "time")) { + return "time"; + } + if (Utilities.existsInList(type, "base64Binary")) { + return "base64Binary"; + } + return type; + } + + private TypeDetails checkForEach(ValidationContext hostContext, List errors, Element vd, Element parent, NodeStack stack, Element expression, String resourceName, TypeDetails t) { + String expr = expression.primitiveValue(); + + List warnings = new ArrayList<>(); + TypeDetails td = null; + try { + ExpressionNode n = fpe.parse(expr); + parent.setUserData(UserDataNames.db_forEach, n); + td = fpe.checkOnTypes(vd, resourceName, t, n, warnings); + } catch (Exception e) { + rule(errors, "2024-11-14", IssueType.EXCEPTION, stack, false, I18nConstants.VIEWDEFINITION_PATH_ERROR, "forEach", e.getMessage()); + return null; + } + if (td != null) { + for (IssueMessage s : warnings) { + warning(errors, "2024-11-14", IssueType.BUSINESSRULE, stack, false, I18nConstants.VIEWDEFINITION_PATH_WARNING, s.getMessage()); + } + } + return td; + + } + + private TypeDetails checkForEachOrNull(ValidationContext hostContext, List errors, Element vd, Element parent, NodeStack stack, Element expression, String resourceName, TypeDetails t) { + String expr = expression.primitiveValue(); + + List warnings = new ArrayList<>(); + TypeDetails td = null; + try { + ExpressionNode n = fpe.parse(expr); + parent.setUserData(UserDataNames.db_forEachOrNull, n); + td = fpe.checkOnTypes(vd, resourceName, t, n, warnings); + } catch (Exception e) { + rule(errors, "2024-11-14", IssueType.EXCEPTION, stack, false, I18nConstants.VIEWDEFINITION_PATH_ERROR, "forEachOrNull", e.getMessage()); + return null; + } + if (td != null) { + for (IssueMessage s : warnings) { + warning(errors, "2024-11-14", IssueType.BUSINESSRULE, stack, false, I18nConstants.VIEWDEFINITION_PATH_WARNING, s.getMessage()); + } + } + return td; + } + + private boolean checkConstant(ValidationContext hostContext, List errors, NodeStack stack, Element constant) { + String name = constant.getNamedChildValue("name"); + warning(errors, "2024-11-14", IssueType.BUSINESSRULE, stack, isValidName(name), I18nConstants.VIEWDEFINITION_CONSTANT_NAME_INVALID); + return true; + } + + private boolean checkWhere(ValidationContext hostContext, List errors, Element vd, NodeStack stack, Element where, String resourceName) { + boolean ok = true; + String expr = where.getNamedChildValue("path"); + if (expr != null) { + List types = new ArrayList<>(); + List warnings = new ArrayList<>(); + types.add(resourceName); + TypeDetails td = null; + try { + ExpressionNode n = fpe.parse(expr); + where.setUserData(UserDataNames.db_path, n); + td = fpe.checkOnTypes(vd, resourceName, types, n, warnings); + } catch (Exception e) { + rule(errors, "2024-11-14", IssueType.EXCEPTION, stack, false, I18nConstants.VIEWDEFINITION_PATH_ERROR, "constant", e.getMessage()); + ok = false; + } + if (td != null) { + if (td.getCollectionStatus() != CollectionStatus.SINGLETON || td.getTypes().size() != 1 || !td.hasType("boolean")) { + rule(errors, "2024-11-14", IssueType.BUSINESSRULE, stack, false, I18nConstants.VIEWDEFINITION_PATH_WRONG_RETURN, td.describe()); + ok = false; + } else { + for (IssueMessage s : warnings) { + warning(errors, "2024-11-14", IssueType.BUSINESSRULE, stack, false, I18nConstants.VIEWDEFINITION_PATH_WARNING, s.getMessage()); + } + } + } + } + return ok; + } + + private boolean isValidName(String name) { + boolean first = true; + for (char c : name.toCharArray()) { + if (!(Character.isAlphabetic(c) || Character.isDigit(c) || (!first && c == '_'))) { + return false; + } + first = false; + } + return true; + } + +} \ No newline at end of file diff --git a/pom.xml b/pom.xml index fab7b90b1..417e23cf0 100644 --- a/pom.xml +++ b/pom.xml @@ -23,7 +23,7 @@ 2.17.0 32.0.1-jre 6.4.1 - 1.6.4 + 1.6.5-SNAPSHOT 2.17.0 5.9.2 1.8.2 From c38420a280305914b9367d36e6b742f1d9b4ee89 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Sat, 16 Nov 2024 21:14:57 +1100 Subject: [PATCH 04/10] expose user data through ResourceWrapper --- .../org/hl7/fhir/convertors/wrapper/ResourceWrapperR4.java | 5 +++++ .../org/hl7/fhir/convertors/wrapper/ResourceWrapperR4B.java | 5 +++++ .../org/hl7/fhir/r5/renderers/utils/ResourceWrapper.java | 1 + .../hl7/fhir/r5/renderers/utils/ResourceWrapperModel.java | 5 +++++ .../hl7/fhir/r5/renderers/utils/ResourceWrapperNative.java | 5 +++++ 5 files changed, 21 insertions(+) diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/wrapper/ResourceWrapperR4.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/wrapper/ResourceWrapperR4.java index 46c3d8060..ded773e74 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/wrapper/ResourceWrapperR4.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/wrapper/ResourceWrapperR4.java @@ -247,4 +247,9 @@ public class ResourceWrapperR4 extends ResourceWrapper { return element.hasUserData(name); } + @Override + public Object getUserData(String name) { + return element.getUserData(name); + } + } \ No newline at end of file diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/wrapper/ResourceWrapperR4B.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/wrapper/ResourceWrapperR4B.java index fa60e02d1..9ae551ef3 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/wrapper/ResourceWrapperR4B.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/wrapper/ResourceWrapperR4B.java @@ -247,4 +247,9 @@ public class ResourceWrapperR4B extends ResourceWrapper { return element.hasUserData(name); } + @Override + public Object getUserData(String name) { + return element.getUserData(name); + } + } \ No newline at end of file diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/ResourceWrapper.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/ResourceWrapper.java index be4ad1c10..92f2dafe4 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/ResourceWrapper.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/ResourceWrapper.java @@ -523,6 +523,7 @@ public abstract class ResourceWrapper { public abstract String primitiveValue(); public abstract boolean isResource(); public abstract boolean hasUserData(String name); + public abstract Object getUserData(String name); } \ No newline at end of file diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/ResourceWrapperModel.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/ResourceWrapperModel.java index f09abd559..b64c98f24 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/ResourceWrapperModel.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/ResourceWrapperModel.java @@ -274,6 +274,11 @@ public class ResourceWrapperModel extends ResourceWrapper { public boolean hasUserData(String name) { return model.hasUserData(name); } + + @Override + public Object getUserData(String name) { + return model.getUserData(name); + } } \ No newline at end of file diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/ResourceWrapperNative.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/ResourceWrapperNative.java index 785f3881e..e1f20650b 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/ResourceWrapperNative.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/ResourceWrapperNative.java @@ -237,4 +237,9 @@ public class ResourceWrapperNative extends ResourceWrapper { return element.hasUserData(name); } + @Override + public Object getUserData(String name) { + return element.getUserData(name); + } + } \ No newline at end of file From 3873d56764a51b282774f36d4daea0bcc71ea6bf Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Sat, 16 Nov 2024 21:15:42 +1100 Subject: [PATCH 05/10] Support ViewDefinition as a custom resource --- .../r5/renderers/ViewDefinitionRenderer.java | 232 +++++++- .../org/hl7/fhir/r5/utils/sql/Column.java | 21 +- .../org/hl7/fhir/r5/utils/sql/Runner.java | 34 +- .../org/hl7/fhir/r5/utils/sql/Validator.java | 2 +- .../type/ViewDefinitionValidator.java | 502 +++++++++++------- 5 files changed, 565 insertions(+), 226 deletions(-) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ViewDefinitionRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ViewDefinitionRenderer.java index 34678644e..2d00a815e 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ViewDefinitionRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ViewDefinitionRenderer.java @@ -10,21 +10,39 @@ import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRFormatError; import org.hl7.fhir.r5.model.CanonicalResource; import org.hl7.fhir.r5.model.Resource; +import org.hl7.fhir.r5.model.ValueSet; import org.hl7.fhir.r5.renderers.utils.RenderingContext; import org.hl7.fhir.r5.renderers.utils.ResourceWrapper; +import org.hl7.fhir.r5.renderers.utils.RenderingContext.GenerationRules; +import org.hl7.fhir.r5.renderers.utils.RenderingContext.KnownLinkType; import org.hl7.fhir.r5.utils.EOperationOutcome; +import org.hl7.fhir.r5.utils.ToolingExtensions; import org.hl7.fhir.r5.utils.UserDataNames; +import org.hl7.fhir.r5.utils.sql.Column; +import org.hl7.fhir.r5.utils.sql.ColumnKind; import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.VersionUtilities; +import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator; +import org.hl7.fhir.utilities.xhtml.NodeType; import org.hl7.fhir.utilities.xhtml.XhtmlNode; +import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Cell; +import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Piece; +import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Row; +import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.TableModel; +import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Title; public class ViewDefinitionRenderer extends ResourceRenderer { public ViewDefinitionRenderer(RenderingContext context) { super(context); } - + + @Override + public boolean renderingUsesValidation() { + return true; + } + @Override public String buildSummary(ResourceWrapper r) throws UnsupportedEncodingException, IOException { return canonicalTitle(r); @@ -35,35 +53,195 @@ public class ViewDefinitionRenderer extends ResourceRenderer { renderResourceTechDetails(vd, x); genSummaryTable(status, x, vd); - XhtmlNode tbl = x.table("grid"); - - // row 1: identity - XhtmlNode tr = tbl.tr(); - tr.para().tx("This view definition produces a table \""+vd.primitiveValue("name")+"\""); - - // row 2: content - tr = tbl.tr(); - CommaSeparatedStringBuilder cb = new CommaSeparatedStringBuilder(", ", " and "); - for (ResourceWrapper v : vd.children("fhirVersion")) { - String ver = v.primitiveValue(); - cb.append(""+VersionUtilities.getNameForVersion(ver)+""); + XhtmlNode p = x.para(); + p.tx("This view acts on the "+vd.primitiveValue("resource")+" resource"); + var vers = vd.children("fhirVersion"); + for (int i = 0; i < vers.size(); i++) { + if (i == 0) { + p.tx(" for version"+(vers.size() == 1 ? "" : "s")+" "); + } else if (i == vers.size() - 1) { + p.tx(" and "); + } else { + p.tx(", "); + } + String ver = vers.get(i).primitiveValue(); + p.ah(VersionUtilities.getSpecUrl(ver)).tx(VersionUtilities.getNameForVersion(ver)); } - String vh = cb.count() == 0 ? "" : cb.count() == 1 ? "version " +cb.toString() : "versions "+cb.toString(); - if (vd.has("resourceProfile")) { - XhtmlNode p = tr.para(); - p.tx("This view acts on "+vh+" "+cb.toString()+" "+vd.primitiveValue("resource")+" using profile ?"); - // todo + p.tx(" using profile ?"); + } + if (vd.has("name")) { + p.tx(" to produce a table named \""); + p.code().tx(vd.primitiveValue("name")); + p.tx("\""); } else { - tr.para().tx("This view acts on "+vh+" "+cb.toString()+" "+vd.primitiveValue("resource")); + p.tx(" to produce a unnamed table"); } - - // row 3: columns - tr = tbl.tr(); - tr.para().tx("This view creates the following columns:"); - // row 4: select tree - tr = tbl.tr(); - tr.para().tx("This view selects the following cells"); - } + if (vd.has("where")) { + List wheres = vd.children("where"); + if (wheres.size() == 1) { + p.tx(" where "); + p.code().tx(wheres.get(0).primitiveValue("path")); + if (wheres.get(0).has("description")) { + p.tx(" ("+wheres.get(0).primitiveValue("description")+")"); + } + p.tx("."); + } else { + p.tx(" where:"); + XhtmlNode ul = x.ul(); + for (ResourceWrapper w : wheres) { + XhtmlNode li = ul.li(); + li.code().tx(wheres.get(0).primitiveValue("path")); + if (wheres.get(0).has("description")) { + li.tx(" ("+wheres.get(0).primitiveValue("description")+")"); + } + } + } + } else { + p.tx("."); + } + + if (vd.hasUserData(UserDataNames.db_columns)) { + x.para().tx("The table contains the following columns:"); + List cols = (List) vd.getUserData(UserDataNames.db_columns); + boolean hasNotes = false; + for (Column col : cols) { + hasNotes = hasNotes || !Utilities.noString(col.getNotes()); + } + XhtmlNode t2 = x.table("grid"); + XhtmlNode tr = t2.tr(); + tr.th().tx("Name"); + tr.th().tx("Fhir Type"); + tr.th().tx("SQL Type"); + tr.th().tx("Collection"); + if (hasNotes) { + tr.th().tx("Notes"); + } + + for (Column col : cols) { + tr = t2.tr(); + tr.td().tx(col.getName()); + tr.td().tx(col.getType()); + tr.td().tx(col.getKind().name()); + tr.td().tx(col.isColl() == null ? "" : col.isColl() ? "Y" : "N"); + if (hasNotes) { + tr.td().tx(col.getNotes()); + } + } + } + if (vd.has("constant")) { + x.para().tx("Constants:"); + + XhtmlNode t2 = x.table("grid"); + XhtmlNode tr = t2.tr(); + tr.th().tx("Name"); + tr.th().tx("Value"); + + for (ResourceWrapper cnst : vd.children("constant")) { + tr = t2.tr(); + tr.td().tx(cnst.primitiveValue("name")); + tr.td().tx(cnst.primitiveValue("value")); + } + } + // row 4: select tree + x.para().tx("Selection Rules:"); + + HierarchicalTableGenerator gen = new HierarchicalTableGenerator(context, context.getDestDir(), context.isInlineGraphics(), true, ""); + TableModel model = gen.new TableModel("vd="+vd.getId(), context.getRules() == GenerationRules.IG_PUBLISHER); + model.setAlternating(true); + if (context.getRules() == GenerationRules.VALID_RESOURCE || context.isInlineGraphics()) { + model.setDocoImg(HierarchicalTableGenerator.help16AsData()); + } else { + model.setDocoImg(Utilities.pathURL(context.getLink(KnownLinkType.SPEC), "help16.png")); + } + model.getTitles().add(gen.new Title(null, model.getDocoRef(), ("Item"), (context.formatPhrase(RenderingContext.QUEST_LINK)), null, 0)); + model.getTitles().add(gen.new Title(null, model.getDocoRef(), ("Coll"), (context.formatPhrase(RenderingContext.QUEST_TEXTFOR)), null, 0)); + model.getTitles().add(gen.new Title(null, model.getDocoRef(), ("Type"), (context.formatPhrase(RenderingContext.QUEST_TIMES)), null, 0)); + model.getTitles().add(gen.new Title(null, model.getDocoRef(), ("Description"), (context.formatPhrase(RenderingContext.QUEST_TYPE_ITEM)), null, 0)); + + // first we add a root for the questionaire itself + Row row = addViewRoot(gen, model.getRows(), vd); + for (ResourceWrapper select : vd.children("select")) { + renderSelect(status, gen, row.getSubRows(), vd, select); + } + XhtmlNode xn = gen.generate(model, context.getLocalPrefix(), 1, null); + x.addChildNode(xn); + } + + private void renderSelect(RenderingStatus status, HierarchicalTableGenerator gen, List rows, ResourceWrapper vd, ResourceWrapper select) { + Row r = gen.new Row(); + rows.add(r); + + r.setIcon("icon_vd_select.png", "Select"); + Cell c1 = gen.new Cell(null, null, "Select", null, null); + r.getCells().add(c1); + r.getCells().add(gen.new Cell(null, null, null, null, null)); + r.getCells().add(gen.new Cell(null, null, null, null, null)); + Cell cell = gen.new Cell(null, null, null, null, null); + if (select.has("forEach")) { + addFHIRPath(cell.getPieces().get(0), "for each ", select.primitiveValue("forEach"), null); + } else if (select.has("forEachOrNull")) { + addFHIRPath(cell.getPieces().get(0), "for each ", select.primitiveValue("forEachOrNull"), ", or null"); + } else { + } + r.getCells().add(cell); + + for (ResourceWrapper column : select.children("column")) { + renderColumn(status, gen, r.getSubRows(), vd, select, column); + } + + for (ResourceWrapper child : select.children("select")) { + renderSelect(status, gen, r.getSubRows(), vd, child); + } + + } + + private void renderColumn(RenderingStatus status, HierarchicalTableGenerator gen, List rows, ResourceWrapper vd, ResourceWrapper select, ResourceWrapper column) { + Row r = gen.new Row(); + rows.add(r); + + r.setIcon("icon_vd_col.png", "Column"); + Cell c1 = gen.new Cell(null, null, column.primitiveValue("name"), null, null); + r.getCells().add(c1); + String coll = column.has("collection") ? "true".equals(column.primitiveValue("collection")) ? "Y" : "N" : ""; + r.getCells().add(gen.new Cell(null, null, coll, null, null)); + r.getCells().add(gen.new Cell(null, null, column.primitiveValue("type"), null, null)); + Cell cell = gen.new Cell(null, null, null, null, null); + addFHIRPath(cell.getPieces().get(0), null, column.primitiveValue("path"), null); + if (column.has("description")) { + cell.addPiece(gen.new Piece("br")); + cell.addPiece(gen.new Piece(null, column.primitiveValue("description"), null)); + } + for (ResourceWrapper tag : column.children("tag")) { + cell.addPiece(gen.new Piece("br")); + cell.addPiece(gen.new Piece(null, tag.primitiveValue("name")+"="+tag.primitiveValue("value"), null)); + } + r.getCells().add(cell); + } + + private void addFHIRPath(Piece p, String pfx, String expr, String sfx) { + XhtmlNode x = new XhtmlNode(NodeType.Element, "span").style("font-size: 11px"); + p.addHtml(x); + if (pfx != null) { + x.tx(pfx); + } + x.code(expr); + if (sfx != null) { + x.tx(sfx); + } + } + + private Row addViewRoot(HierarchicalTableGenerator gen, List rows, ResourceWrapper vd) throws IOException { + Row r = gen.new Row(); + rows.add(r); + + r.setIcon("icon_vd_view.png", context.formatPhrase(RenderingContext.QUEST_ROOT)); + r.getCells().add(gen.new Cell(null, null, vd.primitiveValue("name"), null, null)); + r.getCells().add(gen.new Cell(null, null, "", null, null)); + r.getCells().add(gen.new Cell(null, null, vd.primitiveValue("resource"), null, null)); + r.getCells().add(gen.new Cell(null, null, vd.primitiveValue("description"), null, null)); + return r; + } + } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/sql/Column.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/sql/Column.java index 0fa2f664e..e7f0ac746 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/sql/Column.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/sql/Column.java @@ -6,14 +6,15 @@ public class Column { private int length; private String type; private ColumnKind kind; - private boolean isColl; + private Boolean isColl; private boolean duplicateReported; + private String notes; protected Column() { super(); } - public Column(String name, boolean isColl, String type, ColumnKind kind) { + public Column(String name, Boolean isColl, String type, ColumnKind kind) { super(); this.name = name; this.isColl = isColl; @@ -51,11 +52,11 @@ public class Column { this.type = type; } - public boolean isColl() { + public Boolean isColl() { return isColl; } - public void setColl(boolean isColl) { + public void setColl(Boolean isColl) { this.isColl = isColl; } @@ -94,6 +95,18 @@ public class Column { return "Column [name=" + name + ", length=" + length + ", type=" + type + ", kind=" + kind + ", isColl=" + isColl + "]"; } + + public String getNotes() { + return notes; + } + + public void setNotes(String notes) { + this.notes = notes; + } + + public void addNote(String note) { + this.notes = notes == null ? note : notes+"; "+note; + } } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/sql/Runner.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/sql/Runner.java index 8e4b6c630..bb8de80a3 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/sql/Runner.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/sql/Runner.java @@ -8,6 +8,7 @@ import org.apache.commons.codec.binary.Base64; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.PathEngineException; import org.hl7.fhir.r5.context.IWorkerContext; +import org.hl7.fhir.r5.elementmodel.Element; import org.hl7.fhir.r5.fhirpath.ExpressionNode; import org.hl7.fhir.r5.fhirpath.FHIRPathEngine; import org.hl7.fhir.r5.fhirpath.TypeDetails; @@ -429,12 +430,23 @@ public class Runner implements IEvaluationContext { @Override public TypeDetails resolveConstantType(FHIRPathEngine engine, Object appContext, String name, boolean explicitConstant) throws PathEngineException { if (explicitConstant) { - JsonObject vd = (JsonObject) appContext; - JsonObject constant = findConstant(vd, name.substring(1)); - if (constant != null) { - Base b = (Base) constant.getUserData(UserDataNames.db_value); - if (b != null) { - return new TypeDetails(CollectionStatus.SINGLETON, b.fhirType()); + if (appContext instanceof JsonObject) { + JsonObject vd = (JsonObject) appContext; + JsonObject constant = findConstant(vd, name.substring(1)); + if (constant != null) { + Base b = (Base) constant.getUserData(UserDataNames.db_value); + if (b != null) { + return new TypeDetails(CollectionStatus.SINGLETON, b.fhirType()); + } + } + } else if (appContext instanceof Element) { + Element vd = (Element) appContext; + Element constant = findConstant(vd, name.substring(1)); + if (constant != null) { + Element v = constant.getNamedChild("value"); + if (v != null) { + return new TypeDetails(CollectionStatus.SINGLETON, v.fhirType()); + } } } } @@ -449,6 +461,16 @@ public class Runner implements IEvaluationContext { } return null; } + + private Element findConstant(Element vd, String name) { + for (Element o : vd.getChildren("constant")) { + if (name.equals(o.getNamedChildValue("name"))) { + return o; + } + } + return null; + } + @Override public boolean log(String argument, List focus) { throw new Error("Not implemented yet: log"); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/sql/Validator.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/sql/Validator.java index c15c7dbf9..ab32b4c02 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/sql/Validator.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/sql/Validator.java @@ -432,7 +432,7 @@ public class Validator { } private boolean isSimpleType(String type) { - return Utilities.existsInList(type, "dateTime", "boolean", "integer", "decimal", "string", "base64Binary", "id", "code", "date", "time", "canonical"); + return Utilities.existsInList(type, "dateTime", "boolean", "integer", "decimal", "string", "base64Binary", "id", "code", "date", "time", "canonical", "uri", "url"); } private String simpleType(String type) { diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ViewDefinitionValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ViewDefinitionValidator.java index 7c886f03d..8e8a25699 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ViewDefinitionValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ViewDefinitionValidator.java @@ -1,10 +1,13 @@ package org.hl7.fhir.validation.instance.type; +import java.io.IOException; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import org.hl7.fhir.exceptions.FHIRException; +import org.hl7.fhir.r5.context.IWorkerContext; +import org.hl7.fhir.r5.context.SimpleWorkerContext; import org.hl7.fhir.r5.elementmodel.Element; import org.hl7.fhir.r5.fhirpath.ExpressionNode; import org.hl7.fhir.r5.fhirpath.ExpressionNode.CollectionStatus; @@ -14,8 +17,14 @@ import org.hl7.fhir.r5.fhirpath.TypeDetails; import org.hl7.fhir.r5.utils.UserDataNames; import org.hl7.fhir.r5.utils.sql.Column; import org.hl7.fhir.r5.utils.sql.ColumnKind; +import org.hl7.fhir.r5.utils.sql.Runner; +import org.hl7.fhir.r5.utils.validation.ValidatorSession; +import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; import org.hl7.fhir.utilities.Utilities; +import org.hl7.fhir.utilities.VersionUtilities; import org.hl7.fhir.utilities.i18n.I18nConstants; +import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; +import org.hl7.fhir.utilities.npm.NpmPackage; import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType; import org.hl7.fhir.validation.BaseValidator; @@ -25,72 +34,131 @@ import org.hl7.fhir.validation.instance.utils.ValidationContext; // see also org.hl7.fhir.r5.utils.sql.Validator public class ViewDefinitionValidator extends BaseValidator { + private static class VersionEvaluationContext { + private IWorkerContext context; + private Runner runner; + private FHIRPathEngine fpe; + public VersionEvaluationContext(IWorkerContext context) { + this.context = context; + runner = new Runner(); + runner.setContext(context); - private FHIRPathEngine fpe; + fpe = new FHIRPathEngine(context); // we need our own customised one + fpe.setHostServices(runner); + fpe.setEmitSQLonFHIRWarning(true); + } + } - public ViewDefinitionValidator(BaseValidator parent, FHIRPathEngine fpe) { + public ViewDefinitionValidator(BaseValidator parent) { super(parent); - this.fpe = fpe; } public boolean validateViewDefinition(ValidationContext hostContext, List errors, Element vd, NodeStack stack) throws FHIRException { boolean ok = true; if (warning(errors, "2024-11-14", IssueType.BUSINESSRULE, stack, vd.hasChild("name"), I18nConstants.VIEWDEFINITION_SHOULD_HAVE_NAME)) { - warning(errors, "2024-11-14", IssueType.BUSINESSRULE, stack, isValidName(vd.getNamedChildValue("name")), I18nConstants.VIEWDEFINITION_NAME_INVALID); + warning(errors, "2024-11-14", IssueType.BUSINESSRULE, stack, isValidName(vd.getNamedChildValue("name")), I18nConstants.VIEWDEFINITION_NAME_INVALID, "view", vd.getNamedChildValue("name")); } List columns = new ArrayList<>(); vd.setUserData(UserDataNames.db_columns, columns); - String resourceName = vd.getNamedChildValue("resource"); - if (resourceName != null) { - if (rule(errors, "2024-11-14", IssueType.BUSINESSRULE, stack, context.getResourceNamesAsSet().contains(resourceName), I18nConstants.VIEWDEFINITION_UNKNOWN_RESOURCE)) { - int i = 0; - for (Element constant : vd.getChildren("constant")) { - ok = checkConstant(hostContext, errors, stack.push(constant, i, null, null), constant) && ok; - i++; + List versions = new ArrayList<>(); + if (vd.hasChildren("fhirVersion")) { + for (Element v : vd.getChildren("fhirVersion")) { + String ver = v.primitiveValue(); + if (ver.equals(context.getVersion())) { + makeDefaultContext(versions); + } else { + try { + makeVersionSpecificContext(versions, ver); + } catch (IOException e) { + throw new FHIRException(e); + } } - i = 0; - for (Element where : vd.getChildren("where")) { - ok = checkWhere(hostContext, errors, vd, stack.push(where, i, null, null), where, resourceName) && ok; - i++; - } - TypeDetails t = new TypeDetails(CollectionStatus.SINGLETON, resourceName); - i = 0; - for (Element select : vd.getChildren("select")) { - List cols = new ArrayList(); - ok = checkSelect(hostContext, errors, vd, vd, stack.push(select, i, null, null), select, resourceName, t, cols) && ok; - columns.addAll(cols); - i++; - } - } + } } else { - ok = false; + makeDefaultContext(versions); } + boolean first = true; + for (VersionEvaluationContext vec : versions) { + String vdesc = versions.size() == 1 ? "" : " for version "+VersionUtilities.getNameForVersion(vec.context.getVersion()); + + String resourceName = vd.getNamedChildValue("resource"); + if (resourceName != null) { + if (rule(errors, "2024-11-14", IssueType.BUSINESSRULE, stack, context.getResourceNamesAsSet().contains(resourceName), I18nConstants.VIEWDEFINITION_UNKNOWN_RESOURCE, resourceName)) { + int i = 0; + if (first) { + for (Element constant : vd.getChildren("constant")) { + ok = checkConstant(hostContext, errors, stack.push(constant, i, null, null), constant) && ok; + i++; + } + } + i = 0; + for (Element where : vd.getChildren("where")) { + ok = checkWhere(hostContext, errors, vd, stack.push(where, i, null, null), where, resourceName, vec, vdesc, first) && ok; + i++; + } + + TypeDetails t = new TypeDetails(CollectionStatus.SINGLETON, resourceName); + i = 0; + for (Element select : vd.getChildren("select")) { + ok = checkSelect(hostContext, errors, vd, vd, stack.push(select, i, null, null), select, resourceName, t, columns, vec, vdesc, first) && ok; + i++; + } + } + } else { + ok = false; + } + first = false; + } return ok; } - private boolean checkSelect(ValidationContext hostContext, List errors, Element vd, Element parent, NodeStack stack, Element select, String resourceName, TypeDetails t, List columns) { + private void makeVersionSpecificContext(List versions, String ver) throws FHIRException, IOException { + if (session.getObjects().containsKey(ValidatorSession.VIEW_DEFINITION_CONTEXT+"."+ver)) { + versions.add((VersionEvaluationContext) session.getObjects().get(ValidatorSession.VIEW_DEFINITION_CONTEXT+"."+ver)); + } else { + FilesystemPackageCacheManager pcm = new FilesystemPackageCacheManager.Builder().build(); + NpmPackage npm = pcm.loadPackage(VersionUtilities.packageForVersion(ver)); + SimpleWorkerContext context = new SimpleWorkerContext.SimpleWorkerContextBuilder().withAllowLoadingDuplicates(true).fromPackage(npm); + var vec = new VersionEvaluationContext(context); + session.getObjects().put(ValidatorSession.VIEW_DEFINITION_CONTEXT+"."+context.getVersion(), vec); + versions.add(vec); + } + } + + private void makeDefaultContext(List versions) { + if (session.getObjects().containsKey(ValidatorSession.VIEW_DEFINITION_CONTEXT+"."+context.getVersion())) { + versions.add((VersionEvaluationContext) session.getObjects().get(ValidatorSession.VIEW_DEFINITION_CONTEXT+"."+context.getVersion())); + } else { + var vec = new VersionEvaluationContext(context); + session.getObjects().put(ValidatorSession.VIEW_DEFINITION_CONTEXT+"."+context.getVersion(), vec); + versions.add(vec); + } + } + + private boolean checkSelect(ValidationContext hostContext, List errors, Element vd, Element parent, NodeStack stack, Element select, + String resourceName, TypeDetails t, List columns, VersionEvaluationContext vec, String vdesc, boolean first) { select.setUserData(UserDataNames.db_columns, columns); boolean ok = true; if (select.hasChild("forEach")) { Element e = select.getNamedChild("forEach"); - t = checkForEach(hostContext, errors, vd, select, stack.push(e, -1, null, null), e, resourceName, t); + t = checkForEach(hostContext, errors, vd, select, stack.push(e, -1, null, null), e, resourceName, t, vec, vdesc, first); } else if (select.hasChild("forEachOrNull")) { Element e = select.getNamedChild("forEachOrNull"); - t = checkForEachOrNull(hostContext, errors, vd, select, stack.push(e, -1, null, null), e, resourceName, t); + t = checkForEachOrNull(hostContext, errors, vd, select, stack.push(e, -1, null, null), e, resourceName, t, vec, vdesc, first); } if (t == null) { ok = false; } else { - + if (select.hasChildren("column")) { int i = 0; for (Element e : select.getChildren("column")) { - ok = checkColumn(hostContext, errors, vd,select, stack.push(e, i, null, null), e, resourceName, t, columns) && ok; + ok = checkColumn(hostContext, errors, vd,select, stack.push(e, i, null, null), e, resourceName, t, columns, vec, vdesc, first) && ok; i++; } } @@ -98,7 +166,7 @@ public class ViewDefinitionValidator extends BaseValidator { if (select.hasChildren("select")) { int i = 0; for (Element e : select.getChildren("select")) { - ok = checkSelect(hostContext, errors, vd, select, stack.push(e, i, null, null), e, resourceName, t, columns) && ok; + ok = checkSelect(hostContext, errors, vd, select, stack.push(e, i, null, null), e, resourceName, t, columns, vec, vdesc, first) && ok; i++; } } @@ -106,7 +174,7 @@ public class ViewDefinitionValidator extends BaseValidator { if (select.hasChildren("unionAll")) { int i = 0; for (Element e : select.getChildren("unionAll")) { - ok = checkUnion(hostContext, errors, vd, parent, stack.push(e, i, null, null), e, resourceName, t, columns) && ok; + ok = checkUnion(hostContext, errors, vd, parent, stack.push(e, i, null, null), e, resourceName, t, columns, vec, vdesc, first) && ok; i++; } } @@ -120,46 +188,48 @@ public class ViewDefinitionValidator extends BaseValidator { Set names = new HashSet<>(); for (Column col : columns) { if (col != null) { - if (!names.contains(col.getName())) { - names.add(col.getName()); + String name = col.getName(); + if (!names.contains(name)) { + names.add(name); } else if (!col.isDuplicateReported()) { col.setDuplicateReported(true); - rule(errors, "2024-11-14", IssueType.BUSINESSRULE, stack, false, I18nConstants.VIEWDEFINITION_DUPL_COL_NAME, col.getName()); + rule(errors, "2024-11-14", IssueType.BUSINESSRULE, stack, false, I18nConstants.VIEWDEFINITION_DUPL_COL_NAME, name); } } } } - private boolean checkUnion(ValidationContext hostContext, List errors, Element vd, Element parent, NodeStack stack, Element unionAll, String resourceName, TypeDetails t, List columns) { + private boolean checkUnion(ValidationContext hostContext, List errors, Element vd, Element parent, NodeStack stack, + Element unionAll, String resourceName, TypeDetails t, List columns, VersionEvaluationContext vec, String vdesc, boolean first) { return false; -// List> unionColumns = new ArrayList<>(); -// int i = 0; -// for (JsonElement e : ((JsonArray) a)) { -// if (!(e instanceof JsonObject)) { -// error(path+".unionAll["+i+"]", e, "unionAll["+i+"] is not an object", IssueType.INVALID); -// } else { -// unionColumns.add(checkSelect(vd, path+".unionAll["+i+"]", (JsonObject) e, t)); -// } -// i++; -// } -// if (i < 2) { -// warning(path+".unionAll", a, "unionAll should have more than one item"); -// } -// if (unionColumns.size() > 1) { -// List columns = unionColumns.get(0); -// for (int ic = 1; ic < unionColumns.size(); ic++) { -// String diff = columnDiffs(columns, unionColumns.get(ic)); -// if (diff != null) { -// error(path+".unionAll["+i+"]", ((JsonArray) a).get(ic), "unionAll["+i+"] column definitions do not match: "+diff, IssueType.INVALID); -// } -// } -// a.setUserData(UserDataNames.db_columns, columns); -// return columns; -// } -// } -// return null; + // List> unionColumns = new ArrayList<>(); + // int i = 0; + // for (JsonElement e : ((JsonArray) a)) { + // if (!(e instanceof JsonObject)) { + // error(path+".unionAll["+i+"]", e, "unionAll["+i+"] is not an object", IssueType.INVALID); + // } else { + // unionColumns.add(checkSelect(vd, path+".unionAll["+i+"]", (JsonObject) e, t)); + // } + // i++; + // } + // if (i < 2) { + // warning(path+".unionAll", a, "unionAll should have more than one item"); + // } + // if (unionColumns.size() > 1) { + // List columns = unionColumns.get(0); + // for (int ic = 1; ic < unionColumns.size(); ic++) { + // String diff = columnDiffs(columns, unionColumns.get(ic)); + // if (diff != null) { + // error(path+".unionAll["+i+"]", ((JsonArray) a).get(ic), "unionAll["+i+"] column definitions do not match: "+diff, IssueType.INVALID); + // } + // } + // a.setUserData(UserDataNames.db_columns, columns); + // return columns; + // } + // } + // return null; } - + private String columnDiffs(List list1, List list2) { if (list1.size() == list2.size()) { for (int i = 0; i < list1.size(); i++) { @@ -177,83 +247,113 @@ public class ViewDefinitionValidator extends BaseValidator { } } - private boolean checkColumn(ValidationContext hostContext, List errors, Element vd, Element parent, NodeStack stack, Element column, String resourceName, TypeDetails t, List columns) { - boolean ok = true; + private boolean checkColumn(ValidationContext hostContext, List errors, Element vd, Element parent, NodeStack stack, Element column, String resourceName, + TypeDetails t, List columns, VersionEvaluationContext vec, String vdesc, boolean first) { + boolean ok = false; String expr = column.getNamedChildValue("path"); - - List warnings = new ArrayList<>(); - TypeDetails td = null; - ExpressionNode node = null; - try { - node = fpe.parse(expr); - column.setUserData(UserDataNames.db_path, node); - td = fpe.checkOnTypes(vd, resourceName, t, node, warnings); - } catch (Exception e) { - rule(errors, "2024-11-14", IssueType.EXCEPTION, stack, false, I18nConstants.VIEWDEFINITION_PATH_ERROR, "forEach", e.getMessage()); - ok = false; - } - if (td != null && node != null) { - for (IssueMessage s : warnings) { - warning(errors, "2024-11-14", IssueType.BUSINESSRULE, stack, false, I18nConstants.VIEWDEFINITION_PATH_WARNING, s.getMessage()); - } - String columnName = column.getNamedChildValue("name"); - if (columnName == null) { - List names = node.getDistalNames(); - if (names.size() == 1 && names.get(0) != null) { - columnName = names.get(0); - ok = rule(errors, "2024-11-14", IssueType.INVALID, stack, isValidName(columnName), I18nConstants.VIEWDEFINITION_NAME_ILLEGAL, columnName) && ok; - } else { + if (expr != null) { + ExpressionNode n = getParsedExpression(column, vec.fpe, expr, errors, stack, UserDataNames.db_path); + if (n != null) { + ok = true; + CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder("; "); + List warnings = new ArrayList<>(); + TypeDetails td = null; + try { + td = vec.fpe.checkOnTypes(vd, resourceName, t, n, warnings); + } catch (Exception e) { + rule(errors, "2024-11-14", IssueType.EXCEPTION, stack, false, I18nConstants.VIEWDEFINITION_PATH_ERROR, e.getMessage(), vdesc); ok = false; - rule(errors, "2024-11-14", IssueType.INVALID, stack, false, I18nConstants.VIEWDEFINITION_NAME_REQUIRED); } - } - if (columnName != null) { - column.setUserData(UserDataNames.db_name, columnName); - boolean isColl = false; - if (column.hasChild("collection")) { - isColl = "true".equals(column.getNamedChildValue("collection")); - } - if (isColl) { - if (td.getCollectionStatus() == CollectionStatus.SINGLETON) { - hint(errors, "2024-11-14", IssueType.INFORMATIONAL, stack, false, I18nConstants.VIEWDEFINITION_COLLECTION_NOT_NEEDED, expr, columnName); + if (td != null) { + for (IssueMessage s : warnings) { + warning(errors, "2024-11-14", IssueType.BUSINESSRULE, stack, false, I18nConstants.VIEWDEFINITION_PATH_WARNING, s.getMessage(), vdesc); } - hint(errors, "2024-11-14", IssueType.INFORMATIONAL, stack, false, I18nConstants.VIEWDEFINITION_COLLECTION_NOT_ALWAYS, expr, columnName); - } else { - hint(errors, "2024-11-14", IssueType.INFORMATIONAL, stack, td.getCollectionStatus() == CollectionStatus.SINGLETON, I18nConstants.VIEWDEFINITION_COLLECTION_NEEDED, expr, columnName); - } - Set types = new HashSet<>(); - if (node.isNullSet()) { - types.add("null"); - } else { - // ok collection is sorted - for (String type : td.getTypes()) { - types.add(simpleType(type)); + String columnName = column.getNamedChildValue("name"); + if (columnName == null) { + List names = n.getDistalNames(); + if (names.size() == 1 && names.get(0) != null) { + columnName = names.get(0); + ok = rule(errors, "2024-11-14", IssueType.INVALID, stack, isValidName(columnName), I18nConstants.VIEWDEFINITION_NAME_REQUIRED_HINT, columnName) && ok; + } else { + ok = false; + rule(errors, "2024-11-14", IssueType.INVALID, stack, false, I18nConstants.VIEWDEFINITION_NAME_REQUIRED); + } } + if (columnName != null) { + // ok = rule(errors, "2024-11-14", IssueType.INVALID, stack, false, I18nConstants.VIEWDEFINITION_NAME_ REQUIRED) && ok; + column.setUserData(UserDataNames.db_name, columnName); + Boolean isColl = null; + if (column.hasChild("collection")) { + isColl = "true".equals(column.getNamedChildValue("collection")); + } + if (isColl != null && isColl) { + if (td.getCollectionStatus() == CollectionStatus.SINGLETON) { + if (!hint(errors, "2024-11-14", IssueType.INFORMATIONAL, stack, false, I18nConstants.VIEWDEFINITION_COLLECTION_NOT_NEEDED, expr, columnName)) { + b.append(context.formatMessage(I18nConstants.VIEWDEFINITION_COLLECTION_NOT_NEEDED, expr, columnName)); + } + } + if (!hint(errors, "2024-11-14", IssueType.INFORMATIONAL, stack, false, I18nConstants.VIEWDEFINITION_COLLECTION_NOT_ALWAYS)) { + b.append(context.formatMessage(I18nConstants.VIEWDEFINITION_COLLECTION_NOT_ALWAYS)); + } + } else if (isColl == null) { + if (!hint(errors, "2024-11-14", IssueType.INFORMATIONAL, stack, td.getCollectionStatus() == CollectionStatus.SINGLETON, I18nConstants.VIEWDEFINITION_COLLECTION_NEEDED1, expr, columnName, vdesc)) { + b.append(context.formatMessage(I18nConstants.VIEWDEFINITION_COLLECTION_NEEDED1, expr, columnName, vdesc)); + } + } else { + if (!hint(errors, "2024-11-14", IssueType.INFORMATIONAL, stack, td.getCollectionStatus() == CollectionStatus.SINGLETON, I18nConstants.VIEWDEFINITION_COLLECTION_NEEDED1, expr, columnName, vdesc)) { + b.append(context.formatMessage(I18nConstants.VIEWDEFINITION_COLLECTION_NEEDED2, expr, columnName, vdesc)); + } + } + Set types = new HashSet<>(); + if (n.isNullSet()) { + types.add("null"); + } else { + // ok collection is sorted + for (String type : td.getTypes()) { + types.add(simpleType(type)); + } - String type = column.getNamedChildValue("type"); - if (td.hasType(type)) { - types.clear(); - types.add(simpleType(type)); - } else { - ok = rule(errors, "2024-11-14", IssueType.INVALID, stack, false, I18nConstants.VIEWDEFINITION_TYPE_MISMATCH) && ok; - } - } - if (types.size() != 1) { - ok = rule(errors, "2024-11-14", IssueType.INVALID, stack, false, I18nConstants.VIEWDEFINITION_UNABLE_TO_TYPE, td.describe()) && ok; - } else { - String type = types.iterator().next(); - boolean tok = false; - if (!isSimpleType(type) && !"null".equals(type)) { - hint(errors, "2024-11-14", IssueType.INFORMATIONAL, stack, false, I18nConstants.VIEWDEFINITION_COMPLEX_TYPE, expr, type); - } else { - tok = true; - } - if (tok) { - Column col = new Column(columnName, isColl, type, kindForType(type)); - column.setUserData(UserDataNames.db_column, col); - columns.add(col); - } else { - ok = false; + String type = column.getNamedChildValue("type"); + if (type != null) { + if (td.hasType(type)) { + types.clear(); + types.add(simpleType(type)); + } else { + ok = rule(errors, "2024-11-14", IssueType.INVALID, stack, false, I18nConstants.VIEWDEFINITION_TYPE_MISMATCH, expr, type, td.describe(), vdesc) && ok; + } + } + } + if (types.size() != 1) { + ok = rule(errors, "2024-11-14", IssueType.INVALID, stack, false, I18nConstants.VIEWDEFINITION_UNABLE_TO_TYPE, td.describe(), vdesc) && ok; + } else { + String type = types.iterator().next(); + boolean tok = false; + if (!isSimpleType(type) && !"null".equals(type)) { + hint(errors, "2024-11-14", IssueType.INFORMATIONAL, stack, false, I18nConstants.VIEWDEFINITION_COMPLEX_TYPE, expr, type, vdesc); + } else { + tok = true; + } + if (tok) { + if (first) { + Column col = new Column(columnName, isColl, type, kindForType(type)); + column.setUserData(UserDataNames.db_column, col); + col.setNotes(b.toString()); + columns.add(col); + } else if (b.count() > 0){ + Column col = null; + for (Column c : columns) { + if (c.getName().equals(columnName)) { + col = c; + } + } + if (col != null) { + col.addNote(b.toString()); + } + } + } else { + ok = false; + } + } } } } @@ -283,7 +383,7 @@ public class ViewDefinitionValidator extends BaseValidator { } private boolean isSimpleType(String type) { - return Utilities.existsInList(type, "dateTime", "boolean", "integer", "decimal", "string", "base64Binary", "id", "code", "date", "time", "canonical"); + return Utilities.existsInList(type, "dateTime", "boolean", "integer", "decimal", "string", "base64Binary", "id", "code", "date", "time", "canonical", "uri", "url"); } private String simpleType(String type) { @@ -312,78 +412,89 @@ public class ViewDefinitionValidator extends BaseValidator { return type; } - private TypeDetails checkForEach(ValidationContext hostContext, List errors, Element vd, Element parent, NodeStack stack, Element expression, String resourceName, TypeDetails t) { + private TypeDetails checkForEach(ValidationContext hostContext, List errors, Element vd, Element parent, NodeStack stack, + Element expression, String resourceName, TypeDetails t, VersionEvaluationContext vec, String vdesc, boolean first) { String expr = expression.primitiveValue(); + if (expr != null) { + ExpressionNode n = getParsedExpression(parent, vec.fpe, expr, errors, stack, UserDataNames.db_forEach); + if (n != null) { - List warnings = new ArrayList<>(); - TypeDetails td = null; - try { - ExpressionNode n = fpe.parse(expr); - parent.setUserData(UserDataNames.db_forEach, n); - td = fpe.checkOnTypes(vd, resourceName, t, n, warnings); - } catch (Exception e) { - rule(errors, "2024-11-14", IssueType.EXCEPTION, stack, false, I18nConstants.VIEWDEFINITION_PATH_ERROR, "forEach", e.getMessage()); - return null; - } - if (td != null) { - for (IssueMessage s : warnings) { - warning(errors, "2024-11-14", IssueType.BUSINESSRULE, stack, false, I18nConstants.VIEWDEFINITION_PATH_WARNING, s.getMessage()); + List warnings = new ArrayList<>(); + TypeDetails td = null; + try { + td = vec.fpe.checkOnTypes(vd, resourceName, t, n, warnings); + } catch (Exception e) { + rule(errors, "2024-11-14", IssueType.EXCEPTION, stack, false, I18nConstants.VIEWDEFINITION_PATH_ERROR, e.getMessage(), vdesc); + return null; + } + if (td != null) { + for (IssueMessage s : warnings) { + warning(errors, "2024-11-14", IssueType.BUSINESSRULE, stack, false, I18nConstants.VIEWDEFINITION_PATH_WARNING, s.getMessage(), vdesc); + } + } + return td; } } - return td; + return null; } - private TypeDetails checkForEachOrNull(ValidationContext hostContext, List errors, Element vd, Element parent, NodeStack stack, Element expression, String resourceName, TypeDetails t) { + private TypeDetails checkForEachOrNull(ValidationContext hostContext, List errors, Element vd, Element parent, NodeStack stack, + Element expression, String resourceName, TypeDetails t, VersionEvaluationContext vec, String vdesc, boolean first) { String expr = expression.primitiveValue(); - - List warnings = new ArrayList<>(); - TypeDetails td = null; - try { - ExpressionNode n = fpe.parse(expr); - parent.setUserData(UserDataNames.db_forEachOrNull, n); - td = fpe.checkOnTypes(vd, resourceName, t, n, warnings); - } catch (Exception e) { - rule(errors, "2024-11-14", IssueType.EXCEPTION, stack, false, I18nConstants.VIEWDEFINITION_PATH_ERROR, "forEachOrNull", e.getMessage()); - return null; - } - if (td != null) { - for (IssueMessage s : warnings) { - warning(errors, "2024-11-14", IssueType.BUSINESSRULE, stack, false, I18nConstants.VIEWDEFINITION_PATH_WARNING, s.getMessage()); + if (expr != null) { + ExpressionNode n = getParsedExpression(parent, vec.fpe, expr, errors, stack, UserDataNames.db_forEachOrNull); + if (n != null) { + List warnings = new ArrayList<>(); + TypeDetails td = null; + try { + td = vec.fpe.checkOnTypes(vd, resourceName, t, n, warnings); + } catch (Exception e) { + rule(errors, "2024-11-14", IssueType.EXCEPTION, stack, false, I18nConstants.VIEWDEFINITION_PATH_ERROR, e.getMessage(), vdesc); + return null; + } + if (td != null) { + for (IssueMessage s : warnings) { + warning(errors, "2024-11-14", IssueType.BUSINESSRULE, stack, false, I18nConstants.VIEWDEFINITION_PATH_WARNING, s.getMessage(), vdesc); + } + } + return td; } } - return td; + return null; } private boolean checkConstant(ValidationContext hostContext, List errors, NodeStack stack, Element constant) { String name = constant.getNamedChildValue("name"); - warning(errors, "2024-11-14", IssueType.BUSINESSRULE, stack, isValidName(name), I18nConstants.VIEWDEFINITION_CONSTANT_NAME_INVALID); + warning(errors, "2024-11-14", IssueType.BUSINESSRULE, stack, isValidName(name), I18nConstants.VIEWDEFINITION_NAME_INVALID, "constant", name); return true; } - - private boolean checkWhere(ValidationContext hostContext, List errors, Element vd, NodeStack stack, Element where, String resourceName) { + + private boolean checkWhere(ValidationContext hostContext, List errors, Element vd, NodeStack stack, Element where, + String resourceName, VersionEvaluationContext vec, String vdesc, boolean first) { boolean ok = true; String expr = where.getNamedChildValue("path"); if (expr != null) { - List types = new ArrayList<>(); - List warnings = new ArrayList<>(); - types.add(resourceName); - TypeDetails td = null; - try { - ExpressionNode n = fpe.parse(expr); - where.setUserData(UserDataNames.db_path, n); - td = fpe.checkOnTypes(vd, resourceName, types, n, warnings); - } catch (Exception e) { - rule(errors, "2024-11-14", IssueType.EXCEPTION, stack, false, I18nConstants.VIEWDEFINITION_PATH_ERROR, "constant", e.getMessage()); - ok = false; - } - if (td != null) { - if (td.getCollectionStatus() != CollectionStatus.SINGLETON || td.getTypes().size() != 1 || !td.hasType("boolean")) { - rule(errors, "2024-11-14", IssueType.BUSINESSRULE, stack, false, I18nConstants.VIEWDEFINITION_PATH_WRONG_RETURN, td.describe()); + ExpressionNode n = getParsedExpression(where, vec.fpe, expr, errors, stack, UserDataNames.db_path); + if (n != null) { + List types = new ArrayList<>(); + List warnings = new ArrayList<>(); + types.add(resourceName); + TypeDetails td = null; + try { + td = vec.fpe.checkOnTypes(vd, resourceName, types, n, warnings);} + catch (Exception e) { + rule(errors, "2024-11-14", IssueType.EXCEPTION, stack, false, I18nConstants.VIEWDEFINITION_PATH_ERROR, e.getMessage(), vdesc); ok = false; - } else { - for (IssueMessage s : warnings) { - warning(errors, "2024-11-14", IssueType.BUSINESSRULE, stack, false, I18nConstants.VIEWDEFINITION_PATH_WARNING, s.getMessage()); + } + if (td != null) { + if (td.getCollectionStatus() != CollectionStatus.SINGLETON || td.getTypes().size() != 1 || !td.hasType("boolean")) { + rule(errors, "2024-11-14", IssueType.BUSINESSRULE, stack, false, I18nConstants.VIEWDEFINITION_PATH_WRONG_RETURN, expr, td.describe(), vdesc); + ok = false; + } else { + for (IssueMessage s : warnings) { + warning(errors, "2024-11-14", IssueType.BUSINESSRULE, stack, false, I18nConstants.VIEWDEFINITION_PATH_WARNING, s.getMessage(), vdesc); + } } } } @@ -391,6 +502,21 @@ public class ViewDefinitionValidator extends BaseValidator { return ok; } + private ExpressionNode getParsedExpression(Element focus, FHIRPathEngine fpe, String expr, List errors, NodeStack stack, String udName) { + if (focus.hasUserData(UserDataNames.db_path)) { + return (ExpressionNode) focus.getUserData(udName); + } + + ExpressionNode n = null; + try { + n = fpe.parse(expr); + } catch (Exception e) { + rule(errors, "2024-11-14", IssueType.EXCEPTION, stack, false, I18nConstants.VIEWDEFINITION_PATH_ERROR, e.getMessage(), ""); + } + focus.setUserData(udName, n); + return n; + } + private boolean isValidName(String name) { boolean first = true; for (char c : name.toCharArray()) { From ce06b3f9c5caa822b43257db55a941bd662d0601 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Sat, 16 Nov 2024 21:16:36 +1100 Subject: [PATCH 06/10] refactor UserDataNames round 2 --- .../org/hl7/fhir/r4/utils/sql/Validator.java | 2 +- .../org/hl7/fhir/r5/utils/UserDataNames.java | 9 +++++- .../fhir/utilities/i18n/I18nConstants.java | 32 +++++++++---------- .../src/main/resources/Messages.properties | 17 +++++++++- 4 files changed, 41 insertions(+), 19 deletions(-) diff --git a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/sql/Validator.java b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/sql/Validator.java index 912afcb74..d90181489 100644 --- a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/sql/Validator.java +++ b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/sql/Validator.java @@ -430,7 +430,7 @@ public class Validator { } private boolean isSimpleType(String type) { - return Utilities.existsInList(type, "dateTime", "boolean", "integer", "decimal", "string", "base64Binary", "id", "code", "date", "time", "canonical"); + return Utilities.existsInList(type, "dateTime", "boolean", "integer", "decimal", "string", "base64Binary", "id", "code", "date", "time", "canonical", "uri", "url"); } private String simpleType(String type) { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/UserDataNames.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/UserDataNames.java index 2378f0983..0f33c2419 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/UserDataNames.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/UserDataNames.java @@ -1,5 +1,12 @@ package org.hl7.fhir.r5.utils; +// other than render_src_package, all these are intended to be made consistent in format, using +// the standard format scope-name-name where scope is one of +// lib - core library (most of them) +// validator - validator CLI or web functionality +// pub - IG publisher functionality +// kindling - kindling related functionality + public class UserDataNames { public static final String loader_urls_patched = "old.load.mode"; public static final String loader_custom_resource = "loader-custom-resource"; @@ -34,7 +41,7 @@ public class UserDataNames { public static final String render_external_link = "External.Link"; public static final String render_dict_generator_anchors = "dict.generator.anchors"; public static final String render_presentation = "presentation"; - public static final String render_src_package = "package"; + public static final String render_src_package = "package"; // <--- this value is reused by HAPI and can't change without consultation public static final String renderer_is_generated = "renderer.generated"; public static final String keyview_elementSupported = "elementSupported"; 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 fb522a7f6..728dfc86c 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 @@ -1126,20 +1126,20 @@ public class I18nConstants { public static final String SD_PATH_SLICING_DEPRECATED = "SD_PATH_SLICING_DEPRECATED"; public static final String SD_PATH_NOT_VALID = "SD_PATH_NOT_VALID"; public static final String SD_PATH_ERROR = "SD_PATH_ERROR"; - public static final String VIEWDEFINITION_SHOULD_HAVE_NAME = null; - public static final String VIEWDEFINITION_NAME_INVALID = null; - public static final String VIEWDEFINITION_CONSTANT_NAME_INVALID = null; - public static final String VIEWDEFINITION_PATH_ERROR = null; - public static final String VIEWDEFINITION_PATH_WRONG_RETURN = null; - public static final String VIEWDEFINITION_PATH_WARNING = null; - public static final String VIEWDEFINITION_UNKNOWN_RESOURCE = null; - public static final String VIEWDEFINITION_DUPL_COL_NAME = null; - public static final String VIEWDEFINITION_NAME_ILLEGAL = null; - public static final String VIEWDEFINITION_NAME_REQUIRED = null; - public static final String VIEWDEFINITION_COLLECTION_NOT_NEEDED = null; - public static final String VIEWDEFINITION_COLLECTION_NOT_ALWAYS = null; - public static final String VIEWDEFINITION_COLLECTION_NEEDED = null; - public static final String VIEWDEFINITION_TYPE_MISMATCH = null; - public static final String VIEWDEFINITION_UNABLE_TO_TYPE = null; - public static final String VIEWDEFINITION_COMPLEX_TYPE = null; + public static final String VIEWDEFINITION_SHOULD_HAVE_NAME = "VIEWDEFINITION_SHOULD_HAVE_NAME"; + public static final String VIEWDEFINITION_NAME_INVALID = "VIEWDEFINITION_NAME_INVALID"; + public static final String VIEWDEFINITION_PATH_ERROR = "VIEWDEFINITION_PATH_ERROR"; + public static final String VIEWDEFINITION_PATH_WRONG_RETURN = "VIEWDEFINITION_PATH_WRONG_RETURN"; + public static final String VIEWDEFINITION_PATH_WARNING = "VIEWDEFINITION_PATH_WARNING"; + public static final String VIEWDEFINITION_UNKNOWN_RESOURCE = "VIEWDEFINITION_UNKNOWN_RESOURCE"; + public static final String VIEWDEFINITION_DUPL_COL_NAME = "VIEWDEFINITION_DUPL_COL_NAME"; + public static final String VIEWDEFINITION_NAME_REQUIRED = "VIEWDEFINITION_NAME_REQUIRED"; + public static final String VIEWDEFINITION_NAME_REQUIRED_HINT = "VIEWDEFINITION_NAME_REQUIRED_HINT"; + public static final String VIEWDEFINITION_COLLECTION_NOT_NEEDED = "VIEWDEFINITION_COLLECTION_NOT_NEEDED"; + public static final String VIEWDEFINITION_COLLECTION_NOT_ALWAYS = "VIEWDEFINITION_COLLECTION_NOT_ALWAYS"; + public static final String VIEWDEFINITION_COLLECTION_NEEDED1 = "VIEWDEFINITION_COLLECTION_NEEDED1"; + public static final String VIEWDEFINITION_COLLECTION_NEEDED2 = "VIEWDEFINITION_COLLECTION_NEEDED2"; + public static final String VIEWDEFINITION_TYPE_MISMATCH = "VIEWDEFINITION_TYPE_MISMATCH"; + public static final String VIEWDEFINITION_UNABLE_TO_TYPE = "VIEWDEFINITION_UNABLE_TO_TYPE"; + public static final String VIEWDEFINITION_COMPLEX_TYPE = "VIEWDEFINITION_COMPLEX_TYPE"; } diff --git a/org.hl7.fhir.utilities/src/main/resources/Messages.properties b/org.hl7.fhir.utilities/src/main/resources/Messages.properties index 2e63e64e5..291d626ab 100644 --- a/org.hl7.fhir.utilities/src/main/resources/Messages.properties +++ b/org.hl7.fhir.utilities/src/main/resources/Messages.properties @@ -1156,4 +1156,19 @@ CANONICAL_MULTIPLE_VERSIONS_KNOWN = The version {2} for the {0} {1} is not known SD_PATH_SLICING_DEPRECATED = The discriminator type ''{0}'' has been deprecated. Use type=fixed with a pattern[x] instead SD_PATH_NOT_VALID = The discriminator path ''{0}'' does not appear to be valid for the element that is being sliced ''{1}'' SD_PATH_ERROR = The discriminator path ''{0}'' does not appear to be valid for the element that is being sliced ''{1}'': {2} - +VIEWDEFINITION_SHOULD_HAVE_NAME = No name provided. A name is required in many contexts where a ViewDefinition is used +VIEWDEFINITION_NAME_INVALID = The {0} name ''{1}'' is not valid +VIEWDEFINITION_PATH_ERROR = Expression Error: {0}{1} +VIEWDEFINITION_PATH_WRONG_RETURN = A where path must return a boolean, but the expression ''{0}'' returns a ''{1}'' +VIEWDEFINITION_PATH_WARNING = Expression Warning: {0} +VIEWDEFINITION_UNKNOWN_RESOURCE = The name ''{0}'' is not a valid resource{1} +VIEWDEFINITION_DUPL_COL_NAME = Duplicate Column Name ''{0}'' +VIEWDEFINITION_NAME_REQUIRED = A column name is required +VIEWDEFINITION_NAME_REQUIRED_HINT = A column name is required. The natural name to chose is ''{0}'' (from the path) +VIEWDEFINITION_COLLECTION_NOT_NEEDED = collection is true, but the path statement ''{0}'' can only return single values for the column ''{1}''{2} +VIEWDEFINITION_COLLECTION_NOT_ALWAYS = The column ''{0}'' is defined as a collection, but collections are not supported in all execution contexts +VIEWDEFINITION_COLLECTION_NEEDED1 = This column is not defined as a collection, but the path statement ''{0}'' might return multiple values for the column ''{1}'' for some inputs{2} +VIEWDEFINITION_COLLECTION_NEEDED2 = This column is defined to be not a collection, but the path statement ''{0}'' might return multiple values for the column ''{1}'' for some inputs{2} +VIEWDEFINITION_TYPE_MISMATCH = The path expression ''{0}'' does not return a value of the type ''{1}'' - found ''{2}''{3} +VIEWDEFINITION_UNABLE_TO_TYPE = Unable to determine a type (found ''{0}''){1} +VIEWDEFINITION_COMPLEX_TYPE = Column from path ''{0}'' is a complex type (''{1}''){2}. This is not supported in some Runners From 05cc3b47dad10c748561a1a73efb4a22e4324158 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Sat, 16 Nov 2024 21:18:07 +1100 Subject: [PATCH 07/10] Add support for validator session for internal cache management --- .../fhir/r5/context/SimpleWorkerContext.java | 7 ++-- .../r5/utils/validation/ValidatorSession.java | 35 ++++++++++++++++ .../hl7/fhir/validation/BaseValidator.java | 40 ++++++++++--------- .../hl7/fhir/validation/ValidationEngine.java | 3 +- .../validation/codesystem/BCP47Checker.java | 5 ++- .../validation/codesystem/CPTChecker.java | 5 ++- .../codesystem/CodeSystemBasedChecker.java | 5 ++- .../codesystem/CodeSystemChecker.java | 5 ++- .../codesystem/CodingsObserver.java | 5 ++- .../codesystem/GeneralCodeSystemChecker.java | 5 ++- .../validation/codesystem/LoincChecker.java | 5 ++- .../validation/codesystem/RxNormChecker.java | 5 ++- .../codesystem/SnomedCTChecker.java | 5 ++- .../validation/codesystem/UcumChecker.java | 5 ++- .../instance/InstanceValidator.java | 11 ++--- .../instance/InstanceValidatorFactory.java | 9 +++-- .../instance/type/BundleValidator.java | 1 - .../type/ImplementationGuideValidator.java | 5 ++- .../instance/type/ValueSetValidator.java | 18 ++++----- .../validation/profile/ProfileValidator.java | 5 ++- .../validation/special/R4R5MapTester.java | 2 +- .../instance/InstanceValidatorTests.java | 2 +- 22 files changed, 121 insertions(+), 67 deletions(-) create mode 100644 org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/validation/ValidatorSession.java diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/SimpleWorkerContext.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/SimpleWorkerContext.java index cee46ecd8..22d89b4e5 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/SimpleWorkerContext.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/SimpleWorkerContext.java @@ -71,6 +71,7 @@ import org.hl7.fhir.r5.terminologies.client.TerminologyClientManager; import org.hl7.fhir.r5.terminologies.client.TerminologyClientManager.ITerminologyClientFactory; import org.hl7.fhir.r5.terminologies.client.TerminologyClientR5; import org.hl7.fhir.r5.utils.validation.IResourceValidator; +import org.hl7.fhir.r5.utils.validation.ValidatorSession; import org.hl7.fhir.r5.utils.R5Hacker; import org.hl7.fhir.r5.utils.UserDataNames; import org.hl7.fhir.r5.utils.XVerExtensionManager; @@ -140,8 +141,8 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon } public interface IValidatorFactory { - IResourceValidator makeValidator(IWorkerContext ctxt) throws FHIRException; - IResourceValidator makeValidator(IWorkerContext ctxts, XVerExtensionManager xverManager) throws FHIRException; + IResourceValidator makeValidator(IWorkerContext ctxt, ValidatorSession session) throws FHIRException; + IResourceValidator makeValidator(IWorkerContext ctxts, XVerExtensionManager xverManager, ValidatorSession session) throws FHIRException; } private Questionnaire questionnaire; @@ -611,7 +612,7 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon public IResourceValidator newValidator() throws FHIRException { if (validatorFactory == null) throw new Error(formatMessage(I18nConstants.NO_VALIDATOR_CONFIGURED)); - return validatorFactory.makeValidator(this, xverManager).setJurisdiction(JurisdictionUtilities.getJurisdictionCodingFromLocale(Locale.getDefault().getCountry())); + return validatorFactory.makeValidator(this, xverManager, null).setJurisdiction(JurisdictionUtilities.getJurisdictionCodingFromLocale(Locale.getDefault().getCountry())); } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/validation/ValidatorSession.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/validation/ValidatorSession.java new file mode 100644 index 000000000..6400d8553 --- /dev/null +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/validation/ValidatorSession.java @@ -0,0 +1,35 @@ +package org.hl7.fhir.r5.utils.validation; + +import java.util.HashMap; +import java.util.Map; + +import org.hl7.fhir.utilities.Utilities; + +/** + * Used by the validation infrastructure to cache internal infrastructure that + * will be cast away when the session is closed by the application + */ +public class ValidatorSession { + + public static final String VIEW_DEFINITION_CONTEXT = "VIEW_DEFINITION_CONTEXT"; + + private Map objects = new HashMap<>(); + protected String sessionId; + + public ValidatorSession() { + super(); + sessionId = Utilities.makeUuidLC(); + } + + public String getSessionId() { + return sessionId; + } + + public Map getObjects() { + return objects; + } + + public void close() { + objects.clear(); + } +} 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 fb0bcf3f7..a1bad4902 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 @@ -72,6 +72,7 @@ import org.hl7.fhir.r5.utils.validation.IMessagingServices; import org.hl7.fhir.r5.utils.validation.IResourceValidator; import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor; import org.hl7.fhir.r5.utils.validation.IValidatorResourceFetcher; +import org.hl7.fhir.r5.utils.validation.ValidatorSession; import org.hl7.fhir.r5.utils.validation.ValidationContextCarrier.IValidationContextResourceLoader; import org.hl7.fhir.r5.utils.validation.constants.BestPracticeWarningLevel; import org.hl7.fhir.r5.utils.validation.constants.ReferenceValidationPolicy; @@ -169,7 +170,6 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi protected final String BUNDLE = "Bundle"; protected final String LAST_UPDATED = "lastUpdated"; - protected String sessionId; protected BaseValidator parent; protected IWorkerContext context; protected ValidationTimeTracker timeTracker = new ValidationTimeTracker(); @@ -184,6 +184,7 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi // don't repeatedly raise the same warnings all the time protected Set statusWarnings = new HashSet<>(); + protected ValidatorSession session; protected Source source; // @configuration protected ValidationLevel level = ValidationLevel.HINTS; // @configuration protected Coding jurisdiction; // @configuration @@ -195,15 +196,18 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi protected List usageContexts = new ArrayList(); // @configuration protected ValidationOptions baseOptions = new ValidationOptions(FhirPublication.R5); // @configuration - public BaseValidator(IWorkerContext context, XVerExtensionManager xverManager, boolean debug) { + public BaseValidator(IWorkerContext context, XVerExtensionManager xverManager, boolean debug, ValidatorSession session) { super(); this.context = context; + this.session = session; + if (this.session == null) { + this.session = new ValidatorSession(); + } this.xverManager = xverManager; if (this.xverManager == null) { this.xverManager = new XVerExtensionManager(context); } this.debug = debug; - sessionId = Utilities.makeUuidLC(); policyAdvisor = new BasePolicyAdvisorForFullValidation(ReferenceValidationPolicy.CHECK_VALID); urlRegex = Constants.URI_REGEX_XVER.replace("$$", CommaSeparatedStringBuilder.join("|", context.getResourceNames())); } @@ -211,6 +215,7 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi public BaseValidator(BaseValidator parent) { super(); this.parent = parent; + this.session = parent.session; this.context = parent.context; this.xverManager = parent.xverManager; this.debug = parent.debug; @@ -229,7 +234,6 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi this.usageContexts.addAll(parent.usageContexts); this.baseOptions = parent.baseOptions; this.fetcher = parent.fetcher; - this.sessionId = parent.sessionId; this.policyAdvisor = parent.policyAdvisor; } @@ -1076,8 +1080,8 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi String tt = extractResourceType(ref); ok = VersionUtilities.getCanonicalResourceNames(context.getVersion()).contains(tt); } - if (!ok && stack != null && !sessionId.equals(source.getUserString(UserDataNames.validation_bundle_error))) { - source.setUserData(UserDataNames.validation_bundle_error, sessionId); + if (!ok && stack != null && !session.getSessionId().equals(source.getUserString(UserDataNames.validation_bundle_error))) { + source.setUserData(UserDataNames.validation_bundle_error, session.getSessionId()); hintOrError(!isWarning, errors, NO_RULE_DATE, IssueType.NOTFOUND, stack, false, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOTFOUND, ref, name); } return null; @@ -1085,17 +1089,17 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi if (fragment != null) { int i = countFragmentMatches(el.get(0), fragment); if (i == 0) { - source.setUserData(UserDataNames.validation_bundle_error, sessionId); + source.setUserData(UserDataNames.validation_bundle_error, session.getSessionId()); hintOrError(isNLLink, errors, NO_RULE_DATE, IssueType.NOTFOUND, stack, false, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOTFOUND_FRAGMENT, ref, fragment, name); } else if (i > 1) { - source.setUserData(UserDataNames.validation_bundle_error, sessionId); + source.setUserData(UserDataNames.validation_bundle_error, session.getSessionId()); rule(errors, "2023-11-15", IssueType.INVALID, stack, false, I18nConstants.BUNDLE_BUNDLE_ENTRY_FOUND_MULTIPLE_FRAGMENT, i, ref, fragment, name); } } return el.get(0); } else { - if (stack != null && !sessionId.equals(source.getUserString(UserDataNames.validation_bundle_error))) { - source.setUserData(UserDataNames.validation_bundle_error, sessionId); + if (stack != null && !session.getSessionId().equals(source.getUserString(UserDataNames.validation_bundle_error))) { + source.setUserData(UserDataNames.validation_bundle_error, session.getSessionId()); rule(errors, "2023-11-15", IssueType.INVALID, stack, false, I18nConstants.BUNDLE_BUNDLE_ENTRY_FOUND_MULTIPLE, el.size(), ref, name); } return null; @@ -1111,8 +1115,8 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi if (el.size() == 1) { return el.get(0); } else { - if (stack != null && !sessionId.equals(source.getUserString(UserDataNames.validation_bundle_error))) { - source.setUserData(UserDataNames.validation_bundle_error, sessionId); + if (stack != null && !session.getSessionId().equals(source.getUserString(UserDataNames.validation_bundle_error))) { + source.setUserData(UserDataNames.validation_bundle_error, session.getSessionId()); rule(errors, "2023-11-15", IssueType.INVALID, stack, false, I18nConstants.BUNDLE_BUNDLE_ENTRY_FOUND_MULTIPLE, el.size(), ref, name); } return null; @@ -1133,17 +1137,17 @@ public class BaseValidator implements IValidationContextResourceLoader, IMessagi if (!VersionUtilities.isR4Plus(context.getVersion())) { if (el.size() == 1) { return el.get(0); - } else if (stack != null && !sessionId.equals(source.getUserString(UserDataNames.validation_bundle_error))) { - source.setUserData(UserDataNames.validation_bundle_error, sessionId); + } else if (stack != null && !session.getSessionId().equals(source.getUserString(UserDataNames.validation_bundle_error))) { + source.setUserData(UserDataNames.validation_bundle_error, session.getSessionId()); rulePlural(errors, "2023-11-15", IssueType.INVALID, stack, false, el.size(), I18nConstants.BUNDLE_BUNDLE_ENTRY_NOTFOUND_APPARENT, ref, name, CommaSeparatedStringBuilder.join(",", Utilities.sorted(tl))); } - } else if (stack != null && !sessionId.equals(source.getUserString(UserDataNames.validation_bundle_error))) { - source.setUserData(UserDataNames.validation_bundle_error, sessionId); + } else if (stack != null && !session.getSessionId().equals(source.getUserString(UserDataNames.validation_bundle_error))) { + source.setUserData(UserDataNames.validation_bundle_error, session.getSessionId()); rulePlural(errors, "2023-11-15", IssueType.INVALID, stack, false, el.size(), I18nConstants.BUNDLE_BUNDLE_ENTRY_NOTFOUND_APPARENT, ref, name, CommaSeparatedStringBuilder.join(",", Utilities.sorted(tl))); } } else { - if (stack != null && !sessionId.equals(source.getUserString(UserDataNames.validation_bundle_error))) { - source.setUserData(UserDataNames.validation_bundle_error, sessionId); + if (stack != null && !session.getSessionId().equals(source.getUserString(UserDataNames.validation_bundle_error))) { + source.setUserData(UserDataNames.validation_bundle_error, session.getSessionId()); hintOrError(!isWarning, errors, NO_RULE_DATE, IssueType.NOTFOUND, stack, false, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOTFOUND, ref, name); } } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java index bc642efb3..11e8022bc 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java @@ -71,6 +71,7 @@ import org.hl7.fhir.r5.utils.validation.IMessagingServices; import org.hl7.fhir.r5.utils.validation.IResourceValidator; import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor; import org.hl7.fhir.r5.utils.validation.IValidatorResourceFetcher; +import org.hl7.fhir.r5.utils.validation.ValidatorSession; import org.hl7.fhir.r5.utils.validation.constants.BestPracticeWarningLevel; import org.hl7.fhir.r5.utils.validation.constants.BindingKind; import org.hl7.fhir.r5.utils.validation.constants.CheckDisplayOption; @@ -865,7 +866,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP } public InstanceValidator getValidator(FhirFormat format) throws FHIRException, IOException { - InstanceValidator validator = new InstanceValidator(context, null, null); + InstanceValidator validator = new InstanceValidator(context, null, null, new ValidatorSession()); context.getTxClientManager().setUsage("validation"); validator.setHintAboutNonMustSupport(hintAboutNonMustSupport); validator.setAnyExtensionsAllowed(anyExtensionsAllowed); diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/BCP47Checker.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/BCP47Checker.java index 9049f4544..2359351f9 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/BCP47Checker.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/BCP47Checker.java @@ -5,14 +5,15 @@ import java.util.List; import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.utils.XVerExtensionManager; +import org.hl7.fhir.r5.utils.validation.ValidatorSession; import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.validation.instance.type.ValueSetValidator.PropertyOperation; import org.hl7.fhir.validation.instance.type.ValueSetValidator.PropertyValidationRules; public class BCP47Checker extends CodeSystemChecker { - public BCP47Checker(IWorkerContext context, XVerExtensionManager xverManager, boolean debug, List errors) { - super(context, xverManager, debug, errors); + public BCP47Checker(IWorkerContext context, XVerExtensionManager xverManager, boolean debug, List errors, ValidatorSession session) { + super(context, xverManager, debug, errors, session); } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/CPTChecker.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/CPTChecker.java index 07a0d9235..f3974f930 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/CPTChecker.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/CPTChecker.java @@ -7,6 +7,7 @@ import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.model.CodeSystem.CodeSystemFilterComponent; import org.hl7.fhir.r5.model.CodeSystem.PropertyComponent; import org.hl7.fhir.r5.utils.XVerExtensionManager; +import org.hl7.fhir.r5.utils.validation.ValidatorSession; import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.validation.instance.type.ValueSetValidator.CodeValidationRule; import org.hl7.fhir.validation.instance.type.ValueSetValidator.PropertyFilterType; @@ -15,8 +16,8 @@ import org.hl7.fhir.validation.instance.type.ValueSetValidator.PropertyValidatio public class CPTChecker extends CodeSystemChecker { - public CPTChecker(IWorkerContext context, XVerExtensionManager xverManager, boolean debug, List errors) { - super(context, xverManager, debug, errors); + public CPTChecker(IWorkerContext context, XVerExtensionManager xverManager, boolean debug, List errors, ValidatorSession session) { + super(context, xverManager, debug, errors, session); } @Override diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/CodeSystemBasedChecker.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/CodeSystemBasedChecker.java index a55bf7048..480760d5a 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/CodeSystemBasedChecker.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/CodeSystemBasedChecker.java @@ -10,6 +10,7 @@ import org.hl7.fhir.r5.model.CodeSystem.CodeSystemFilterComponent; import org.hl7.fhir.r5.model.CodeSystem.PropertyComponent; import org.hl7.fhir.r5.model.Enumerations.FilterOperator; import org.hl7.fhir.r5.utils.XVerExtensionManager; +import org.hl7.fhir.r5.utils.validation.ValidatorSession; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.validation.instance.type.ValueSetValidator.CodeValidationRule; @@ -21,8 +22,8 @@ public class CodeSystemBasedChecker extends CodeSystemChecker { private CodeSystem cs; - public CodeSystemBasedChecker(IWorkerContext context, XVerExtensionManager xverManager, boolean debug, List errors, CodeSystem cs) { - super(context, xverManager, debug, errors); + public CodeSystemBasedChecker(IWorkerContext context, XVerExtensionManager xverManager, boolean debug, List errors, CodeSystem cs, ValidatorSession session) { + super(context, xverManager, debug, errors, session); this.cs = cs; } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/CodeSystemChecker.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/CodeSystemChecker.java index 9508896c3..3567516fb 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/CodeSystemChecker.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/CodeSystemChecker.java @@ -6,6 +6,7 @@ import java.util.List; import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.elementmodel.Element; import org.hl7.fhir.r5.utils.XVerExtensionManager; +import org.hl7.fhir.r5.utils.validation.ValidatorSession; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.i18n.I18nConstants; import org.hl7.fhir.utilities.validation.ValidationMessage; @@ -23,8 +24,8 @@ public abstract class CodeSystemChecker extends BaseValidator { private boolean hasDisplay = false; protected List errors; - protected CodeSystemChecker(IWorkerContext context, XVerExtensionManager xverManager, boolean debug, List errors) { - super(context, xverManager, debug); + protected CodeSystemChecker(IWorkerContext context, XVerExtensionManager xverManager, boolean debug, List errors, ValidatorSession session) { + super(context, xverManager, debug, session); this.errors = errors; } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/CodingsObserver.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/CodingsObserver.java index 0e1555dd4..4fdb05f41 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/CodingsObserver.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/CodingsObserver.java @@ -14,6 +14,7 @@ import org.hl7.fhir.r5.model.CodeableConcept; import org.hl7.fhir.r5.model.Coding; import org.hl7.fhir.r5.terminologies.utilities.CodingValidationRequest; import org.hl7.fhir.r5.utils.XVerExtensionManager; +import org.hl7.fhir.r5.utils.validation.ValidatorSession; import org.hl7.fhir.utilities.i18n.I18nConstants; import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType; @@ -33,8 +34,8 @@ public class CodingsObserver extends BaseValidator { } } - public CodingsObserver(@Nonnull IWorkerContext context, @Nonnull XVerExtensionManager xverManager, boolean debug) { - super(context, xverManager, debug); + public CodingsObserver(@Nonnull IWorkerContext context, @Nonnull XVerExtensionManager xverManager, boolean debug, ValidatorSession session) { + super(context, xverManager, debug, session); this.context = context; } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/GeneralCodeSystemChecker.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/GeneralCodeSystemChecker.java index a314eea22..f0c5a26d8 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/GeneralCodeSystemChecker.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/GeneralCodeSystemChecker.java @@ -4,12 +4,13 @@ import java.util.List; import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.utils.XVerExtensionManager; +import org.hl7.fhir.r5.utils.validation.ValidatorSession; import org.hl7.fhir.utilities.validation.ValidationMessage; public class GeneralCodeSystemChecker extends CodeSystemChecker { - public GeneralCodeSystemChecker(IWorkerContext context, XVerExtensionManager xverManager, boolean debug, List errors) { - super(context, xverManager, debug, errors); + public GeneralCodeSystemChecker(IWorkerContext context, XVerExtensionManager xverManager, boolean debug, List errors, ValidatorSession session) { + super(context, xverManager, debug, errors, session); // TODO Auto-generated constructor stub } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/LoincChecker.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/LoincChecker.java index 0618af6b2..c5ffd4415 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/LoincChecker.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/LoincChecker.java @@ -5,6 +5,7 @@ import java.util.List; import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.utils.XVerExtensionManager; +import org.hl7.fhir.r5.utils.validation.ValidatorSession; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.validation.instance.type.ValueSetValidator.CodeValidationRule; @@ -14,8 +15,8 @@ import org.hl7.fhir.validation.instance.type.ValueSetValidator.PropertyValidatio public class LoincChecker extends CodeSystemChecker { - public LoincChecker(IWorkerContext context, XVerExtensionManager xverManager, boolean debug, List errors) { - super(context, xverManager, debug, errors); + public LoincChecker(IWorkerContext context, XVerExtensionManager xverManager, boolean debug, List errors, ValidatorSession session) { + super(context, xverManager, debug, errors, session); } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/RxNormChecker.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/RxNormChecker.java index 9de081831..a11ea027f 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/RxNormChecker.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/RxNormChecker.java @@ -5,6 +5,7 @@ import java.util.List; import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.utils.XVerExtensionManager; +import org.hl7.fhir.r5.utils.validation.ValidatorSession; import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.validation.instance.type.ValueSetValidator.CodeValidationRule; import org.hl7.fhir.validation.instance.type.ValueSetValidator.PropertyFilterType; @@ -13,8 +14,8 @@ import org.hl7.fhir.validation.instance.type.ValueSetValidator.PropertyValidatio public class RxNormChecker extends CodeSystemChecker { - public RxNormChecker(IWorkerContext context, XVerExtensionManager xverManager, boolean debug, List errors) { - super(context, xverManager, debug, errors); + public RxNormChecker(IWorkerContext context, XVerExtensionManager xverManager, boolean debug, List errors, ValidatorSession session) { + super(context, xverManager, debug, errors, session); } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/SnomedCTChecker.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/SnomedCTChecker.java index 048f906d5..1424c0005 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/SnomedCTChecker.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/SnomedCTChecker.java @@ -7,6 +7,7 @@ import java.util.List; import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.elementmodel.Element; import org.hl7.fhir.r5.utils.XVerExtensionManager; +import org.hl7.fhir.r5.utils.validation.ValidatorSession; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.i18n.I18nConstants; import org.hl7.fhir.utilities.validation.ValidationMessage; @@ -23,8 +24,8 @@ public class SnomedCTChecker extends CodeSystemChecker { private boolean hasTag = false; private List tags = new ArrayList<>(); - public SnomedCTChecker(IWorkerContext context, XVerExtensionManager xverManager, boolean debug, List errors) { - super(context, xverManager, debug, errors); + public SnomedCTChecker(IWorkerContext context, XVerExtensionManager xverManager, boolean debug, List errors, ValidatorSession session) { + super(context, xverManager, debug, errors, session); } public void checkConcept(String code, String display) { diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/UcumChecker.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/UcumChecker.java index e18cf56f7..0a35345b3 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/UcumChecker.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/UcumChecker.java @@ -5,6 +5,7 @@ import java.util.List; import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.utils.XVerExtensionManager; +import org.hl7.fhir.r5.utils.validation.ValidatorSession; import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.validation.instance.type.ValueSetValidator.CodeValidationRule; import org.hl7.fhir.validation.instance.type.ValueSetValidator.PropertyFilterType; @@ -13,8 +14,8 @@ import org.hl7.fhir.validation.instance.type.ValueSetValidator.PropertyValidatio public class UcumChecker extends CodeSystemChecker { - public UcumChecker(IWorkerContext context, XVerExtensionManager xverManager, boolean debug, List errors) { - super(context, xverManager, debug, errors); + public UcumChecker(IWorkerContext context, XVerExtensionManager xverManager, boolean debug, List errors, ValidatorSession session) { + super(context, xverManager, debug, errors, session); } 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 805ae5226..3880b7322 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 @@ -172,6 +172,7 @@ import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor.CodedContentVal import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor.ElementValidationAction; import org.hl7.fhir.r5.utils.validation.IValidationProfileUsageTracker; import org.hl7.fhir.r5.utils.validation.IValidatorResourceFetcher; +import org.hl7.fhir.r5.utils.validation.ValidatorSession; import org.hl7.fhir.r5.utils.validation.constants.BestPracticeWarningLevel; import org.hl7.fhir.r5.utils.validation.constants.BindingKind; import org.hl7.fhir.r5.utils.validation.constants.CheckDisplayOption; @@ -618,8 +619,8 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat private boolean unknownCodeSystemsCauseErrors; private boolean noExperimentalContent; - public InstanceValidator(@Nonnull IWorkerContext theContext, @Nonnull IEvaluationContext hostServices, @Nonnull XVerExtensionManager xverManager) { - super(theContext, xverManager, false); + public InstanceValidator(@Nonnull IWorkerContext theContext, @Nonnull IEvaluationContext hostServices, @Nonnull XVerExtensionManager xverManager, ValidatorSession session) { + super(theContext, xverManager, false, session); start = System.currentTimeMillis(); this.externalHostServices = hostServices; this.profileUtilities = new ProfileUtilities(theContext, null, null); @@ -632,7 +633,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat source = Source.InstanceValidator; fpe.setDoNotEnforceAsSingletonRule(!VersionUtilities.isR5VerOrLater(theContext.getVersion())); fpe.setAllowDoubleQuotes(allowDoubleQuotesInFHIRPath); - codingObserver = new CodingsObserver(theContext, xverManager, debug); + codingObserver = new CodingsObserver(theContext, xverManager, debug, session); } @Override @@ -5946,9 +5947,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } else if (element.getType().equals("ValueSet")) { return new ValueSetValidator(this).validateValueSet(valContext, errors, element, stack) && ok; } else if (element.getType().equals("ViewDefinition")) { - return new ViewDefinitionValidator(this, fpe).validateViewDefinition(valContext, errors, element, stack) && ok; + return new ViewDefinitionValidator(this).validateViewDefinition(valContext, errors, element, stack) && ok; } else if (element.getType().equals("ImplementationGuide")) { - return new ImplementationGuideValidator(this.context, xverManager, debug).validateImplementationGuide(valContext, errors, element, stack) && ok; + return new ImplementationGuideValidator(this.context, xverManager, debug, session).validateImplementationGuide(valContext, errors, element, stack) && ok; } else if ("http://hl7.org/fhir/uv/sql-on-fhir/StructureDefinition/ViewDefinition".equals(element.getProperty().getStructure().getUrl())) { if (element.getNativeObject() != null && element.getNativeObject() instanceof JsonObject) { JsonObject json = (JsonObject) element.getNativeObject(); diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidatorFactory.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidatorFactory.java index 67bc55ba2..2533ee911 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidatorFactory.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidatorFactory.java @@ -37,17 +37,18 @@ import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.context.SimpleWorkerContext.IValidatorFactory; import org.hl7.fhir.r5.utils.XVerExtensionManager; import org.hl7.fhir.r5.utils.validation.IResourceValidator; +import org.hl7.fhir.r5.utils.validation.ValidatorSession; public class InstanceValidatorFactory implements IValidatorFactory { @Override - public IResourceValidator makeValidator(IWorkerContext ctxt, XVerExtensionManager xverManager) throws FHIRException { - return new InstanceValidator(ctxt, null, xverManager); + public IResourceValidator makeValidator(IWorkerContext ctxt, XVerExtensionManager xverManager, ValidatorSession session) throws FHIRException { + return new InstanceValidator(ctxt, null, xverManager, session); } @Override - public IResourceValidator makeValidator(IWorkerContext ctxt) throws FHIRException { - return new InstanceValidator(ctxt, null, null); + public IResourceValidator makeValidator(IWorkerContext ctxt, ValidatorSession session) throws FHIRException { + return new InstanceValidator(ctxt, null, null, session); } } \ No newline at end of file diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/BundleValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/BundleValidator.java index a4ec1a17d..4f4cc0bc7 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/BundleValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/BundleValidator.java @@ -75,7 +75,6 @@ public class BundleValidator extends BaseValidator { public boolean validateBundle(List errors, Element bundle, NodeStack stack, boolean checkSpecials, ValidationContext hostContext, PercentageTracker pct, ValidationMode mode) { boolean ok = true; - sessionId = Utilities.makeUuidLC(); String type = bundle.getNamedChildValue(TYPE, false); type = StringUtils.defaultString(type); diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ImplementationGuideValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ImplementationGuideValidator.java index c7a7081a8..39f41308f 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ImplementationGuideValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ImplementationGuideValidator.java @@ -29,6 +29,7 @@ import org.hl7.fhir.r5.terminologies.utilities.TerminologyServiceErrorClass; import org.hl7.fhir.r5.terminologies.utilities.ValidationResult; import org.hl7.fhir.r5.utils.XVerExtensionManager; import org.hl7.fhir.r5.utils.validation.ValidationContextCarrier; +import org.hl7.fhir.r5.utils.validation.ValidatorSession; import org.hl7.fhir.r5.utils.validation.ValidationContextCarrier.ValidationContextResourceProxy; import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; import org.hl7.fhir.utilities.FhirPublication; @@ -53,8 +54,8 @@ import ca.uhn.fhir.util.ObjectUtil; public class ImplementationGuideValidator extends BaseValidator { - public ImplementationGuideValidator(IWorkerContext context, XVerExtensionManager xverManager, boolean debug) { - super(context, xverManager, debug); + public ImplementationGuideValidator(IWorkerContext context, XVerExtensionManager xverManager, boolean debug, ValidatorSession session) { + super(context, xverManager, debug, session); } public boolean validateImplementationGuide(ValidationContext valContext, List errors, Element ig, NodeStack stack) { diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ValueSetValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ValueSetValidator.java index 47bc5b25d..f75d72247 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ValueSetValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ValueSetValidator.java @@ -132,21 +132,21 @@ public class ValueSetValidator extends BaseValidator { private CodeSystemChecker getSystemValidator(String system, List errors) { if (system == null) { - return new GeneralCodeSystemChecker(context, xverManager, debug, errors); + return new GeneralCodeSystemChecker(context, xverManager, debug, errors, session); } switch (system) { - case "http://snomed.info/sct" :return new SnomedCTChecker(context, xverManager, debug, errors); - case "http://loinc.org": return new LoincChecker(context, xverManager, debug, errors); - case "http://www.nlm.nih.gov/research/umls/rxnorm": return new RxNormChecker(context, xverManager, debug, errors); - case "http://unitsofmeasure.org": return new UcumChecker(context, xverManager, debug, errors); - case "http://www.ama-assn.org/go/cpt": return new CPTChecker(context, xverManager, debug, errors); - case "urn:ietf:bcp:47": return new BCP47Checker(context, xverManager, debug, errors); + case "http://snomed.info/sct" :return new SnomedCTChecker(context, xverManager, debug, errors, session); + case "http://loinc.org": return new LoincChecker(context, xverManager, debug, errors, session); + case "http://www.nlm.nih.gov/research/umls/rxnorm": return new RxNormChecker(context, xverManager, debug, errors, session); + case "http://unitsofmeasure.org": return new UcumChecker(context, xverManager, debug, errors, session); + case "http://www.ama-assn.org/go/cpt": return new CPTChecker(context, xverManager, debug, errors, session); + case "urn:ietf:bcp:47": return new BCP47Checker(context, xverManager, debug, errors, session); default: CodeSystem cs = context.fetchCodeSystem(system); if (cs != null) { - return new CodeSystemBasedChecker(context, xverManager, debug, errors, cs); + return new CodeSystemBasedChecker(context, xverManager, debug, errors, cs, session); } else { - return new GeneralCodeSystemChecker(context, xverManager, debug, errors); + return new GeneralCodeSystemChecker(context, xverManager, debug, errors, session); } } } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/profile/ProfileValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/profile/ProfileValidator.java index a02dd685d..a1ea3b290 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/profile/ProfileValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/profile/ProfileValidator.java @@ -42,6 +42,7 @@ import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent; import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind; import org.hl7.fhir.r5.utils.XVerExtensionManager; +import org.hl7.fhir.r5.utils.validation.ValidatorSession; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType; @@ -54,8 +55,8 @@ public class ProfileValidator extends BaseValidator { private boolean allowDoubleQuotesInFHIRPath = false; private FHIRPathEngine fpe; - public ProfileValidator(IWorkerContext context, XVerExtensionManager xverManager) { - super(context, xverManager, false); + public ProfileValidator(IWorkerContext context, XVerExtensionManager xverManager, ValidatorSession session) { + super(context, xverManager, false, session); fpe = new FHIRPathEngine(context); fpe.setAllowDoubleQuotes(allowDoubleQuotesInFHIRPath); } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/special/R4R5MapTester.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/special/R4R5MapTester.java index 0679966dc..0aca9bbe5 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/special/R4R5MapTester.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/special/R4R5MapTester.java @@ -187,7 +187,7 @@ public class R4R5MapTester implements IValidatorResourceFetcher { loadPackage("hl7.fhir.r4.core#4.0.1", false); loadPackage("hl7.fhir.r4b.core#4.3.0", false); - validator = new InstanceValidator(context, null, null); + validator = new InstanceValidator(context, null, null, null); validator.setSuppressLoincSnomedMessages(true); validator.setResourceIdRule(IdStatus.REQUIRED); validator.setBestPracticeWarningLevel(BestPracticeWarningLevel.Warning); diff --git a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/instance/InstanceValidatorTests.java b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/instance/InstanceValidatorTests.java index dd57e41e5..09234c908 100644 --- a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/instance/InstanceValidatorTests.java +++ b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/instance/InstanceValidatorTests.java @@ -37,7 +37,7 @@ class InstanceValidatorTests { IWorkerContext context = mock(IWorkerContext.class); when(context.getLocale()).thenReturn(Locale.KOREA); when(context.getVersion()).thenReturn("5.0.1"); - InstanceValidator instanceValidator = new InstanceValidator(context, null, null); + InstanceValidator instanceValidator = new InstanceValidator(context, null, null, null); when(context.validateCode((ValidationOptions) any(ValidationOptions.class), (CodeableConcept) any(CodeableConcept.class), (ValueSet)any(ValueSet.class))).thenReturn(new ValidationResult(ValidationMessage.IssueSeverity.NULL, "Blah!", Collections.emptyList())); From 39bcaa05df36d182b655311ac37c2fa2d734e68c Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Sat, 16 Nov 2024 21:21:37 +1100 Subject: [PATCH 08/10] fix broken link for custom resources --- .../fhir/r5/renderers/StructureDefinitionRenderer.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/StructureDefinitionRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/StructureDefinitionRenderer.java index 12c4e922d..49dec0be2 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/StructureDefinitionRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/StructureDefinitionRenderer.java @@ -1876,7 +1876,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer { c.getPieces().add(gen.new Piece("#"+ed.getElement().getPath(), tail(ed.getElement().getPath()), ed.getElement().getPath())); } else { c.getPieces().add(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_SEE)+" ", null)); - c.getPieces().add(gen.new Piece(pfx(corePath, ed.getSource().getWebPath())+"#"+ed.getElement().getPath(), tail(ed.getElement().getPath())+" ("+ed.getSource().getTypeName()+")", ed.getElement().getPath())); + c.getPieces().add(gen.new Piece(typePath(corePath, ed.getSource())+"#"+ed.getElement().getPath(), tail(ed.getElement().getPath())+" ("+ed.getSource().getTypeName()+")", ed.getElement().getPath())); } } return c; @@ -2055,6 +2055,14 @@ public class StructureDefinitionRenderer extends ResourceRenderer { } + private String typePath(String cp, StructureDefinition source) { + if (source.hasUserData(UserDataNames.loader_custom_resource)) { + return source.getWebPath(); + } else { + return pfx(cp, source.getWebPath()); + } + } + private boolean hasMultipleVersions(List list) { Set vl = new HashSet<>(); for (CanonicalResource cr : list) { From 65133a76f60780418699fbcf6d48434a13379cba Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Sat, 16 Nov 2024 21:21:53 +1100 Subject: [PATCH 09/10] support for custom resources --- .../main/java/org/hl7/fhir/r5/renderers/ResourceRenderer.java | 4 ++++ .../main/java/org/hl7/fhir/r5/utils/NPMPackageGenerator.java | 3 ++- .../main/java/org/hl7/fhir/utilities/xhtml/XhtmlFluent.java | 4 ++++ .../main/java/org/hl7/fhir/utilities/xhtml/XhtmlParser.java | 1 - 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ResourceRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ResourceRenderer.java index fb643d31b..2d99f765a 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ResourceRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ResourceRenderer.java @@ -66,6 +66,10 @@ public abstract class ResourceRenderer extends DataRenderer { return this; } + public boolean renderingUsesValidation() { + return false; + } + /** * Just build the narrative that would go in the resource (per @renderResource()), but don't put it in the resource * @param dr diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/NPMPackageGenerator.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/NPMPackageGenerator.java index 9ba2fab0f..3a3de4915 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/NPMPackageGenerator.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/NPMPackageGenerator.java @@ -75,7 +75,7 @@ import org.hl7.fhir.utilities.npm.ToolsVersion; public class NPMPackageGenerator { public enum Category { - RESOURCE, EXAMPLE, OPENAPI, SCHEMATRON, RDF, OTHER, TOOL, TEMPLATE, JEKYLL, TEST; + RESOURCE, EXAMPLE, OPENAPI, SCHEMATRON, RDF, OTHER, TOOL, TEMPLATE, JEKYLL, TEST, CUSTOM; private String getDirectory() { switch (this) { @@ -89,6 +89,7 @@ public class NPMPackageGenerator { case JEKYLL: return "package/jekyll/"; case TEST: return "package/tests/"; case TOOL: return "package/bin/"; + case CUSTOM: return "package/custom/"; } return "/"; } diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlFluent.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlFluent.java index 79a90d5fa..30a5b036e 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlFluent.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlFluent.java @@ -119,6 +119,10 @@ public abstract class XhtmlFluent { return addTag("ul"); } + public XhtmlNode ol() { + return addTag("ol"); + } + public XhtmlNode li() { return addTag("li"); } diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlParser.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlParser.java index 2709e434b..f13b26088 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlParser.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlParser.java @@ -586,7 +586,6 @@ public class XhtmlParser { if (t.length() > 0) { lastText = t; - // System.out.println(t); node.addText(t).setLocation(markLocation()); s.setLength(0); } From aea8621bb1d5e9c73b85ab3e3303310618c1c042 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Mon, 18 Nov 2024 06:04:16 +1100 Subject: [PATCH 10/10] fix error in test --- .../org/hl7/fhir/validation/tests/ValidationEngineTests.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationEngineTests.java b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationEngineTests.java index 4d7dc537b..68c22b186 100644 --- a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationEngineTests.java +++ b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationEngineTests.java @@ -11,6 +11,7 @@ import org.hl7.fhir.r5.model.OperationOutcome; import org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity; import org.hl7.fhir.r5.model.OperationOutcome.OperationOutcomeIssueComponent; import org.hl7.fhir.r5.test.utils.TestingUtilities; +import org.hl7.fhir.r5.utils.OperationOutcomeUtilities; import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; import org.hl7.fhir.utilities.FhirPublication; import org.hl7.fhir.utilities.settings.FhirSettings; @@ -89,6 +90,7 @@ public class ValidationEngineTests { } catch (Exception e) { e.printStackTrace(); System.err.println("Thread " + index + " failed"); + outcomes[index] = OperationOutcomeUtilities.outcomeFromTextError(e.getMessage()); } }); t.start();