From ef86cf7652368d2486bc4cb2a29d36b8e3b6e837 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Thu, 19 Dec 2024 13:16:48 +1100 Subject: [PATCH] Fix logical model rendering to use type characteristics for can-be-target --- .../hl7/fhir/r5/context/IWorkerContext.java | 7 ++- .../StructureDefinitionRenderer.java | 43 +++++++++++++------ .../expansion/ValueSetExpander.java | 6 +-- .../utilities/ValueSetProcessBase.java | 18 ++++++++ .../validation/ValueSetValidator.java | 2 +- 5 files changed, 59 insertions(+), 17 deletions(-) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/IWorkerContext.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/IWorkerContext.java index 6b00b3d4e..16843fc51 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/IWorkerContext.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/IWorkerContext.java @@ -51,6 +51,7 @@ import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.TerminologyServiceException; import org.hl7.fhir.r5.context.IWorkerContext.OIDDefinition; import org.hl7.fhir.r5.context.IWorkerContext.OIDDefinitionComparer; +import org.hl7.fhir.r5.context.IWorkerContext.ITerminologyOperationDetails; import org.hl7.fhir.r5.elementmodel.Element; import org.hl7.fhir.r5.formats.IParser; import org.hl7.fhir.r5.formats.ParserType; @@ -109,6 +110,10 @@ import javax.annotation.Nonnull; public interface IWorkerContext { + public interface ITerminologyOperationDetails { + + public void seeSupplement(CodeSystem supp); + } /** @deprecated This interface only exists to provide backward compatibility for the following two projects: clinical-reasoning @@ -513,7 +518,7 @@ public interface IWorkerContext { * @return * @throws FHIRException */ - ValueSetExpansionOutcome expandVS(ConceptSetComponent inc, boolean hierarchical, boolean noInactive) throws TerminologyServiceException; + ValueSetExpansionOutcome expandVS(ITerminologyOperationDetails opCtxt, ConceptSetComponent inc, boolean hierarchical, boolean noInactive) throws TerminologyServiceException; /** * get/set the locale used when creating messages 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 49dec0be2..39c745b2f 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 @@ -1580,20 +1580,18 @@ public class StructureDefinitionRenderer extends ResourceRenderer { if (profile.getKind() == StructureDefinitionKind.LOGICAL) { Extension lt = ToolingExtensions.getExtension(profile, ToolingExtensions.EXT_LOGICAL_TARGET); - if (lt == null || !lt.hasValueBooleanType()) { + List tc = ToolingExtensions.getExtensions(profile, ToolingExtensions.EXT_TYPE_CHARACTERISTICS); + Boolean canBeTarget = checkCanBeTarget(lt, tc); + if (canBeTarget == null) { + // don't say anything + } else if (canBeTarget) { if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } - c.addPiece(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_NOT_MARK), null).addStyle("font-weight:bold")); ; - } else if (lt.getValue().hasExtension(ToolingExtensions.EXT_DAR)) { - } else if (!lt.getValueBooleanType().hasValue()) { - if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } - c.addPiece(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_CAN_TARGET), null).addStyle("font-weight:bold")); ; - } else if (lt.getValueBooleanType().booleanValue()) { + c.addPiece(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_CAN_TARGET), null).addStyle("font-weight:bold")); + } else { if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } - c.addPiece(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_CAN_TARGET), null).addStyle("font-weight:bold")); - } else { - if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } - c.addPiece(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_CAN_TARGET), null).addStyle("font-weight:bold")); - } + c.addPiece(gen.new Piece(null, context.formatPhrase(RenderingContext.STRUC_DEF_NOT_MARK), null).addStyle("font-weight:bold")); + } + String ps = ToolingExtensions.readStringExtension(profile, ToolingExtensions.EXT_PROFILE_STYLE); if (ps != null) { if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } @@ -1765,6 +1763,27 @@ public class StructureDefinitionRenderer extends ResourceRenderer { return c; } + private Boolean checkCanBeTarget(Extension lt, List tc) { + Boolean res = null; + if (lt == null || !lt.hasValueBooleanType() || lt.getValue().hasExtension(ToolingExtensions.EXT_DAR)) { + } else if (!lt.getValueBooleanType().hasValue()) { + res = null; // GDG Dec-2024: this is true, but changed to null + } else if (lt.getValueBooleanType().booleanValue()) { + res = true; + } else { + res = false; // GDG Dec 2024- this was true, but evidently should be false, so fixed + } + if (res == null && !tc.isEmpty()) { + res = false; + for (Extension t : tc) { + if (t.hasValueCodeType() && "can-be-target".equals(t.getValueCodeType().primitiveValue())) { + res = true; + } + } + } + return res; + } + private boolean isAbstractBaseProfile(String source) { StructureDefinition sd = context.getContext().fetchResource(StructureDefinition.class, source); return (sd != null) && sd.getAbstract() && sd.hasUrl() && sd.getUrl().startsWith("http://hl7.org/fhir/StructureDefinition/"); 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 b616fc92f..4ac14f91d 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 @@ -120,6 +120,7 @@ import org.hl7.fhir.r5.terminologies.providers.CodeSystemProvider; import org.hl7.fhir.r5.terminologies.providers.CodeSystemProviderExtension; import org.hl7.fhir.r5.terminologies.utilities.TerminologyOperationContext; import org.hl7.fhir.r5.terminologies.utilities.TerminologyOperationContext.TerminologyServiceProtectionException; +import org.hl7.fhir.r5.terminologies.utilities.ValueSetProcessBase.TerminologyOperationDetails; import org.hl7.fhir.r5.terminologies.utilities.TerminologyServiceErrorClass; import org.hl7.fhir.r5.terminologies.utilities.ValueSetProcessBase; import org.hl7.fhir.r5.utils.ToolingExtensions; @@ -609,7 +610,7 @@ public class ValueSetExpander extends ValueSetProcessBase { if (exc.hasSystem()) { CodeSystem cs = context.fetchSupplementedCodeSystem(exc.getSystem()); if ((cs == null || cs.getContent() != CodeSystemContentMode.COMPLETE) && context.supportsSystem(exc.getSystem(), opContext.getOptions().getFhirVersion())) { - ValueSetExpansionOutcome vse = context.expandVS(exc, false, false); + ValueSetExpansionOutcome vse = context.expandVS(new TerminologyOperationDetails(requiredSupplements), exc, false, false); ValueSet valueset = vse.getValueset(); if (valueset == null) throw failTSE("Error Expanding ValueSet: "+vse.getError()); @@ -655,7 +656,6 @@ public class ValueSetExpander extends ValueSetProcessBase { } public ValueSetExpansionOutcome expand(ValueSet source, Parameters expParams) { - allErrors.clear(); try { opContext.seeContext(source.getVersionedUrl()); @@ -1050,7 +1050,7 @@ public class ValueSetExpander extends ValueSetProcessBase { return; } - ValueSetExpansionOutcome vso = context.expandVS(inc, heirarchical, noInactive); + ValueSetExpansionOutcome vso = context.expandVS(new TerminologyOperationDetails(requiredSupplements), inc, heirarchical, noInactive); if (vso.getError() != null) { throw failTSE("Unable to expand imported value set: " + vso.getError()); } 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 7628fc60c..6f4bca562 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 @@ -5,8 +5,10 @@ import java.util.List; import org.hl7.fhir.r5.context.ContextUtilities; import org.hl7.fhir.r5.context.IWorkerContext; +import org.hl7.fhir.r5.context.IWorkerContext.ITerminologyOperationDetails; import org.hl7.fhir.r5.model.BooleanType; import org.hl7.fhir.r5.model.CanonicalResource; +import org.hl7.fhir.r5.model.CodeSystem; import org.hl7.fhir.r5.model.DataType; import org.hl7.fhir.r5.model.Enumerations.PublicationStatus; import org.hl7.fhir.r5.model.OperationOutcome.IssueType; @@ -27,6 +29,22 @@ import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity; public class ValueSetProcessBase { + public static class TerminologyOperationDetails implements ITerminologyOperationDetails { + + private List supplements; + + public TerminologyOperationDetails(List supplements) { + super(); + this.supplements = supplements; + } + + @Override + public void seeSupplement(CodeSystem supp) { + supplements.remove(supp.getUrl()); + supplements.remove(supp.getVersionedUrl()); + } + } + public enum OpIssueCode { NotInVS, ThisNotInVS, InvalidCode, Display, DisplayComment, NotFound, CodeRule, VSProcessing, InferFailed, StatusCheck, InvalidData; 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 634c1f108..9d87baafb 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 @@ -1291,7 +1291,7 @@ public class ValueSetValidator extends ValueSetProcessBase { sys.add(vsi.getSystem()); } else { // ok, we'll try to expand this one then - ValueSetExpansionOutcome vse = context.expandVS(vsi, false, false); + ValueSetExpansionOutcome vse = context.expandVS(new TerminologyOperationDetails(requiredSupplements), vsi, false, false); if (vse.isOk()) { if (!checkSystems(vse.getValueset().getExpansion().getContains(), code, sys, problems)) { return false;