From 6b1ae35ef319f5b6cc462978f778a9fdc1585b29 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Sat, 17 Dec 2022 07:11:06 +1100 Subject: [PATCH] * Add validator support for fhir_comments in R2/R2B (#1042) + Add validator checks around versions in extension URLs --- RELEASE_NOTES.md | 3 ++- .../hl7/fhir/r5/elementmodel/JsonParser.java | 13 ++++++++++ .../fhir/utilities/i18n/I18nConstants.java | 6 +++++ .../src/main/resources/Messages.properties | 7 +++++ .../instance/InstanceValidator.java | 26 ++++++++++++++++--- 5 files changed, 51 insertions(+), 4 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 7b06c6ab5..8006835eb 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,6 +1,7 @@ ## Validator Changes -* no changes +* Add support for fhir_comments in R2/R2B +* Add validator checking around versions in extension URLs ## Other code changes diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/JsonParser.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/JsonParser.java index c782a9085..8ce07f498 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/JsonParser.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/JsonParser.java @@ -66,6 +66,7 @@ import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; import org.hl7.fhir.utilities.StringPair; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; +import org.hl7.fhir.utilities.VersionUtilities; import org.hl7.fhir.utilities.i18n.I18nConstants; import org.hl7.fhir.utilities.json.model.JsonArray; import org.hl7.fhir.utilities.json.model.JsonComment; @@ -236,6 +237,18 @@ public class JsonParser extends ParserBase { if (sd != null) { Property property = new Property(context, sd.getSnapshot().getElementFirstRep(), sd, element.getProperty().getUtils()); parseChildItem(path, recognisedChildren, element, null, property); + } else if ("fhir_comments".equals(e.getKey()) && (VersionUtilities.isR2BVer(context.getVersion()) || VersionUtilities.isR2Ver(context.getVersion()))) { + if (!e.getValue().getValue().isJsonArray()) { + logError("2022-12-17", line(e.getValue().getValue()), col(e.getValue().getValue()), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.ILLEGAL_COMMENT_TYPE, e.getValue().getValue().type().toName()), IssueSeverity.ERROR); + } else { + for (JsonElement c : e.getValue().getValue().asJsonArray()) { + if (!c.isJsonString()) { + logError("2022-12-17", line(e.getValue().getValue()), col(e.getValue().getValue()), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.ILLEGAL_COMMENT_TYPE, c.type().toName()), IssueSeverity.ERROR); + } else { + element.getComments().add(c.asString()); + } + } + } } else { logError(ValidationMessage.NO_RULE_DATE, line(e.getValue().getValue()), col(e.getValue().getValue()), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.UNRECOGNISED_PROPERTY_, e.getKey()), IssueSeverity.ERROR); } 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 3c3808c06..a3d31691e 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 @@ -767,6 +767,12 @@ public class I18nConstants { public static final String JSON_COMMA_MISSING = "JSON_COMMA_MISSING"; public static final String JSON_COMMA_EXTRA = "JSON_COMMA_EXTRA"; public static final String JSON_COMMENTS_NOT_ALLOWED = "JSON_COMMENTS_NOT_ALLOWED"; + public static final String EXT_VER_URL_NO_MATCH = "EXT_VER_URL_NO_MATCH"; + public static final String EXT_VER_URL_IGNORE = "EXT_VER_URL_IGNORE"; + public static final String EXT_VER_URL_MISLEADING = "EXT_VER_URL_MISLEADING"; + public static final String EXT_VER_URL_NOT_ALLOWED = "EXT_VER_URL_NOT_ALLOWED"; + public static final String EXT_VER_URL_REVERSION = "EXT_VER_URL_REVERSION"; + public static final String ILLEGAL_COMMENT_TYPE = "ILLEGAL_COMMENT_TYPE"; } diff --git a/org.hl7.fhir.utilities/src/main/resources/Messages.properties b/org.hl7.fhir.utilities/src/main/resources/Messages.properties index e561e55c6..53d2bf1e3 100644 --- a/org.hl7.fhir.utilities/src/main/resources/Messages.properties +++ b/org.hl7.fhir.utilities/src/main/resources/Messages.properties @@ -817,3 +817,10 @@ BUNDLE_LINK_STYELSHEET_EXTERNAL = External Stylesheets other than https://hl7.or BUNDLE_LINK_STYELSHEET_INSECURE = The stylesheet reference is not secure BUNDLE_LINK_STYELSHEET_LINKABLE = The stylesheet reference is not a resolvable link BUNDLE_LINK_STYELSHEET_NOT_FOUND = The stylesheet reference could not be resolved in this bundle +EXT_VER_URL_NO_MATCH = Extension URLs don't have versions. The validator wasn't able to resolve this URL with or without version-based resolution +EXT_VER_URL_IGNORE = Extension URLs don't have versions. The validator has ignored the version and processed the extension anyway +EXT_VER_URL_MISLEADING = The extension URL contains a '|' which makes it look like a versioned URL, but it's not, and this is confusing for implementers +EXT_VER_URL_NOT_ALLOWED = The extension URL must not contain a version +EXT_VER_URL_REVERSION = The extension URL must not contain a version. The extension was validated against version {0} of the extension +ILLEGAL_COMMENT_TYPE = The fhir_comments property must be an array of strings + \ No newline at end of file diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java index 304b9dfc2..e9da90745 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 @@ -1826,15 +1826,35 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat private StructureDefinition checkExtension(ValidatorHostContext hostContext, List errors, String path, Element resource, Element container, Element element, ElementDefinition def, StructureDefinition profile, NodeStack stack, NodeStack containerStack, String extensionUrl, PercentageTracker pct, ValidationMode mode) throws FHIRException { String url = element.getNamedChildValue("url"); + String u = url.contains("|") ? url.substring(0, url.indexOf("|")) : url; boolean isModifier = element.getName().equals("modifierExtension"); assert def.getIsModifier() == isModifier; long t = System.nanoTime(); - StructureDefinition ex = Utilities.isAbsoluteUrl(url) ? context.fetchResource(StructureDefinition.class, url) : null; - timeTracker.sd(t); + StructureDefinition ex = Utilities.isAbsoluteUrl(u) ? context.fetchResource(StructureDefinition.class, u) : null; if (ex == null) { - ex = getXverExt(errors, path, element, url); + ex = getXverExt(errors, path, element, u); } + if (url.contains("|")) { + if (ex == null) { + ex = Utilities.isAbsoluteUrl(url) ? context.fetchResource(StructureDefinition.class, url) : null; + if (ex == null) { + warning(errors, "2022-12-17", IssueType.INVALID, element.line(), element.col(), path + "[url='" + url + "']", false, I18nConstants.EXT_VER_URL_NO_MATCH); + } else { + rule(errors, "2022-12-17", IssueType.INVALID, element.line(), element.col(), path + "[url='" + url + "']", false, I18nConstants.EXT_VER_URL_IGNORE); + } + } else { + if (url.equals(ex.getUrl())) { + warning(errors, NO_RULE_DATE, IssueType.INVALID, element.line(), element.col(), path + "[url='" + url + "']", false, I18nConstants.EXT_VER_URL_MISLEADING); + } else if (url.equals(ex.getVersionedUrl())) { + rule(errors, NO_RULE_DATE, IssueType.INVALID, element.line(), element.col(), path + "[url='" + url + "']", false, I18nConstants.EXT_VER_URL_NOT_ALLOWED); + } else { // + rule(errors, NO_RULE_DATE, IssueType.INVALID, element.line(), element.col(), path + "[url='" + url + "']", false, I18nConstants.EXT_VER_URL_REVERSION, ex.getVersion()); + } + } + } + + timeTracker.sd(t); if (ex == null) { if (extensionUrl != null && !isAbsolute(url)) { if (extensionUrl.equals(profile.getUrl())) {