From fedfa88ffbdbf6ecb925af2ba4ee17ad217d2dad Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Thu, 1 Dec 2022 08:16:00 +1100 Subject: [PATCH] refactor resource reference resolution to use package dependencies whereever possible --- .../CapabilityStatementComparer.java | 2 +- .../fhir/r5/comparison/ComparisonSession.java | 6 +- .../fhir/r5/comparison/ProfileComparer.java | 67 ++--- .../fhir/r5/conformance/ProfileUtilities.java | 156 +++++----- .../r5/conformance/R5ExtensionsLoader.java | 8 +- .../fhir/r5/context/BaseWorkerContext.java | 145 +++++---- .../r5/context/CanonicalResourceManager.java | 279 ++++++++++++------ .../hl7/fhir/r5/context/ContextUtilities.java | 2 +- .../hl7/fhir/r5/context/IWorkerContext.java | 159 +++------- .../fhir/r5/context/SimpleWorkerContext.java | 36 ++- .../org/hl7/fhir/r5/elementmodel/Element.java | 2 +- .../hl7/fhir/r5/model/PackageInformation.java | 99 +++++++ .../java/org/hl7/fhir/r5/model/Resource.java | 18 ++ .../hl7/fhir/r5/openapi/OpenApiGenerator.java | 21 +- .../r5/renderers/ActorDefinitionRenderer.java | 4 +- .../fhir/r5/renderers/ConceptMapRenderer.java | 4 +- .../hl7/fhir/r5/renderers/DataRenderer.java | 4 +- .../OperationDefinitionRenderer.java | 12 +- .../r5/renderers/ProfileDrivenRenderer.java | 11 +- .../r5/renderers/QuestionnaireRenderer.java | 26 +- .../QuestionnaireResponseRenderer.java | 8 +- .../r5/renderers/RequirementsRenderer.java | 14 +- .../fhir/r5/renderers/ResourceRenderer.java | 6 +- .../r5/renderers/SearchParameterRenderer.java | 2 +- .../r5/renderers/TerminologyRenderer.java | 10 +- .../fhir/r5/renderers/ValueSetRenderer.java | 42 +-- .../fhir/r5/renderers/utils/BaseWrappers.java | 2 + .../fhir/r5/renderers/utils/DOMWrappers.java | 8 +- .../r5/renderers/utils/DirectWrappers.java | 2 +- .../r5/renderers/utils/ElementWrappers.java | 8 +- .../terminologies/ValueSetCheckerSimple.java | 12 +- .../terminologies/ValueSetExpanderSimple.java | 8 +- .../fhir/r5/utils/DefinitionNavigator.java | 15 +- .../org/hl7/fhir/r5/utils/FHIRPathEngine.java | 31 +- .../hl7/fhir/r5/utils/PackageHackerR5.java | 4 +- .../hl7/fhir/r5/utils/ResourceUtilities.java | 26 ++ .../test/CanonicalResourceManagerTests.java | 49 ++- .../validation/ValidationMessage.java | 6 +- .../hl7/fhir/utilities/DateTimeUtilTests.java | 2 + .../hl7/fhir/validation/BaseValidator.java | 6 +- .../hl7/fhir/validation/ValidationEngine.java | 4 +- .../instance/InstanceValidator.java | 50 ++-- .../instance/type/QuestionnaireValidator.java | 2 +- pom.xml | 2 +- 44 files changed, 849 insertions(+), 531 deletions(-) create mode 100644 org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/PackageInformation.java diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/CapabilityStatementComparer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/CapabilityStatementComparer.java index dd0825825..94fd857d1 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/CapabilityStatementComparer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/CapabilityStatementComparer.java @@ -483,7 +483,7 @@ public class CapabilityStatementComparer extends CanonicalResourceComparer { if (sdFocus.getUrl().equals(sdOther.getUrl()) && sdFocus.getVersion().equals(sdOther.getVersion())) { return true; } - sdFocus = ctxt.fetchResource(StructureDefinition.class, sdFocus.getBaseDefinition()); + sdFocus = ctxt.fetchResource(StructureDefinition.class, sdFocus.getBaseDefinition(), sdFocus); } return false; } 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 b718482c7..b897f0647 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 @@ -60,12 +60,12 @@ public class ComparisonSession { return title; } - public ResourceComparison compare(String left, String right) throws DefinitionException, FHIRFormatError, IOException { - CanonicalResource l = (CanonicalResource) contextLeft.fetchResource(Resource.class, left); + public ResourceComparison compare(String left, Resource leftSource, String right, Resource rightSource) throws DefinitionException, FHIRFormatError, IOException { + CanonicalResource l = (CanonicalResource) contextLeft.fetchResource(Resource.class, left, leftSource); if (l == null) { throw new DefinitionException("Unable to resolve "+left); } - CanonicalResource r = (CanonicalResource) contextRight.fetchResource(Resource.class, right); + CanonicalResource r = (CanonicalResource) contextRight.fetchResource(Resource.class, right, rightSource); if (r == null) { throw new DefinitionException("Unable to resolve "+right); } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/ProfileComparer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/ProfileComparer.java index 30fdf10cc..eda5387a3 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/ProfileComparer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/ProfileComparer.java @@ -29,6 +29,7 @@ import org.hl7.fhir.r5.model.Enumeration; import org.hl7.fhir.r5.model.Enumerations.BindingStrength; import org.hl7.fhir.r5.model.IntegerType; import org.hl7.fhir.r5.model.PrimitiveType; +import org.hl7.fhir.r5.model.Resource; import org.hl7.fhir.r5.model.StringType; import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.r5.model.StructureDefinition.TypeDerivationRule; @@ -226,7 +227,7 @@ public class ProfileComparer extends CanonicalResourceComparer { subset.setMin(intersectMin(leftMin, rightMin)); subset.setMax(intersectMax(leftMax, rightMax, left.current().getMax(), right.current().getMax())); - superset.getType().addAll(unionTypes(comp, res, path, left.current().getType(), right.current().getType())); + superset.getType().addAll(unionTypes(comp, res, path, left.current().getType(), right.current().getType(), left.getStructure(), right.getStructure())); subset.getType().addAll(intersectTypes(comp, res, subset, path, left.current().getType(), right.current().getType())); rule(comp, res, !subset.getType().isEmpty() || (!left.current().hasType() && !right.current().hasType()), path, "Type Mismatch: "+typeCode(left)+" vs "+typeCode(right)); // @@ -234,7 +235,7 @@ public class ProfileComparer extends CanonicalResourceComparer { superset.setMaxLengthElement(unionMaxLength(left.current().getMaxLength(), right.current().getMaxLength())); subset.setMaxLengthElement(intersectMaxLength(left.current().getMaxLength(), right.current().getMaxLength())); if (left.current().hasBinding() || right.current().hasBinding()) { - compareBindings(comp, res, subset, superset, path, left.current(), right.current()); + compareBindings(comp, res, subset, superset, path, left.current(), right.current(), left.getStructure(), right.getStructure()); } // note these are backwards superset.getConstraint().addAll(intersectConstraints(path, left.current().getConstraint(), right.current().getConstraint())); @@ -312,10 +313,10 @@ public class ProfileComparer extends CanonicalResourceComparer { // it's possible that one of these profiles walks into a data type and the other doesn't // if it does, we have to load the children for that data into the profile that doesn't // walk into it - if (lc.isEmpty() && !rc.isEmpty() && right.current().getType().size() == 1 && left.hasTypeChildren(right.current().getType().get(0))) - lc = left.childrenFromType(right.current().getType().get(0)); - if (rc.isEmpty() && !lc.isEmpty() && left.current().getType().size() == 1 && right.hasTypeChildren(left.current().getType().get(0))) - rc = right.childrenFromType(left.current().getType().get(0)); + if (lc.isEmpty() && !rc.isEmpty() && right.current().getType().size() == 1 && left.hasTypeChildren(right.current().getType().get(0), left.getStructure())) + lc = left.childrenFromType(right.current().getType().get(0), right.getStructure()); + if (rc.isEmpty() && !lc.isEmpty() && left.current().getType().size() == 1 && right.hasTypeChildren(left.current().getType().get(0), right.getStructure())) + rc = right.childrenFromType(left.current().getType().get(0), left.getStructure()); List matchR = new ArrayList<>(); for (DefinitionNavigator l : lc) { @@ -529,16 +530,16 @@ public class ProfileComparer extends CanonicalResourceComparer { return Integer.toString(defn.current().getMin())+".."+defn.current().getMax(); } - private Collection unionTypes(ProfileComparison comp, StructuralMatch res, String path, List left, List right) throws DefinitionException, IOException, FHIRFormatError { + private Collection unionTypes(ProfileComparison comp, StructuralMatch res, String path, List left, List right, Resource leftSrc, Resource rightSrc) throws DefinitionException, IOException, FHIRFormatError { List result = new ArrayList(); for (TypeRefComponent l : left) - checkAddTypeUnion(comp, res, path, result, l, session.getContextLeft()); + checkAddTypeUnion(comp, res, path, result, l, session.getContextLeft(), leftSrc); for (TypeRefComponent r : right) - checkAddTypeUnion(comp, res, path, result, r, session.getContextRight()); + checkAddTypeUnion(comp, res, path, result, r, session.getContextRight(), rightSrc); return result; } - private void checkAddTypeUnion(ProfileComparison comp, StructuralMatch res, String path, List results, TypeRefComponent nw, IWorkerContext ctxt) throws DefinitionException, IOException, FHIRFormatError { + private void checkAddTypeUnion(ProfileComparison comp, StructuralMatch res, String path, List results, TypeRefComponent nw, IWorkerContext ctxt, Resource nwSource) throws DefinitionException, IOException, FHIRFormatError { boolean pfound = false; boolean tfound = false; nw = nw.copy(); @@ -558,8 +559,8 @@ public class ProfileComparer extends CanonicalResourceComparer { 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()); - StructureDefinition sdnw = ctxt.fetchResource(StructureDefinition.class, nw.getProfile().get(0).getValue()); + StructureDefinition sdex = ((IWorkerContext) ex.getUserData("ctxt")).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; @@ -586,8 +587,8 @@ public class ProfileComparer extends CanonicalResourceComparer { 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()); - StructureDefinition sdnw = ctxt.fetchResource(StructureDefinition.class, nw.getTargetProfile().get(0).getValue()); + StructureDefinition sdex = ((IWorkerContext) ex.getUserData("ctxt")).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; @@ -633,7 +634,7 @@ public class ProfileComparer extends CanonicalResourceComparer { if (right.getUrl().equals(sd.getBaseDefinition())) { return true; } - sd = sd.hasBaseDefinition() ? ctxt.fetchResource(StructureDefinition.class, sd.getBaseDefinition()) : null; + sd = sd.hasBaseDefinition() ? ctxt.fetchResource(StructureDefinition.class, sd.getBaseDefinition(), sd) : null; } return false; } @@ -653,8 +654,8 @@ public class ProfileComparer extends CanonicalResourceComparer { pfound = true; c.setProfile(r.getProfile()); } else { - StructureDefinition sdl = resolveProfile(comp, res, path, l.getProfile().get(0).getValue(), comp.getLeft().getName(), session.getContextLeft()); - StructureDefinition sdr = resolveProfile(comp, res, path, r.getProfile().get(0).getValue(), comp.getRight().getName(), session.getContextRight()); + StructureDefinition sdl = resolveProfile(comp, res, path, l.getProfile().get(0).getValue(), comp.getLeft().getName(), session.getContextLeft(), comp.getLeft()); + StructureDefinition sdr = resolveProfile(comp, res, path, r.getProfile().get(0).getValue(), comp.getRight().getName(), session.getContextRight(), comp.getRight()); if (sdl != null && sdr != null) { if (sdl == sdr) { pfound = true; @@ -680,8 +681,8 @@ public class ProfileComparer extends CanonicalResourceComparer { tfound = true; c.setTargetProfile(r.getTargetProfile()); } else { - StructureDefinition sdl = resolveProfile(comp, res, path, l.getTargetProfile().get(0).getValue(), comp.getLeft().getName(), session.getContextLeft()); - StructureDefinition sdr = resolveProfile(comp, res, path, r.getTargetProfile().get(0).getValue(), comp.getRight().getName(), session.getContextRight()); + StructureDefinition sdl = resolveProfile(comp, res, path, l.getTargetProfile().get(0).getValue(), comp.getLeft().getName(), session.getContextLeft(), comp.getLeft()); + StructureDefinition sdr = resolveProfile(comp, res, path, r.getTargetProfile().get(0).getValue(), comp.getRight().getName(), session.getContextRight(), comp.getRight()); if (sdl != null && sdr != null) { if (matches(sdl, sdr)) { tfound = true; @@ -721,7 +722,7 @@ public class ProfileComparer extends CanonicalResourceComparer { return b.toString(); } - private boolean compareBindings(ProfileComparison comp, StructuralMatch res, ElementDefinition subset, ElementDefinition superset, String path, ElementDefinition lDef, ElementDefinition rDef) throws FHIRFormatError, DefinitionException, IOException { + private boolean compareBindings(ProfileComparison comp, StructuralMatch res, ElementDefinition subset, ElementDefinition superset, String path, ElementDefinition lDef, ElementDefinition rDef, Resource leftSrc, Resource rightSrc) throws FHIRFormatError, DefinitionException, IOException { assert(lDef.hasBinding() || rDef.hasBinding()); if (!lDef.hasBinding()) { subset.setBinding(rDef.getBinding()); @@ -750,25 +751,25 @@ public class ProfileComparer extends CanonicalResourceComparer { if (right.getStrength() == BindingStrength.PREFERRED && left.getStrength() == BindingStrength.EXAMPLE && !Base.compareDeep(left.getValueSet(), right.getValueSet(), false)) { vm(IssueSeverity.INFORMATION, "Example/preferred bindings differ at "+path+" using binding from "+comp.getRight().getName(), path, comp.getMessages(), res.getMessages()); subset.setBinding(right); - superset.setBinding(unionBindings(comp, res, path, left, right)); + superset.setBinding(unionBindings(comp, res, path, left, right, leftSrc, rightSrc)); } else { if ((right.getStrength() != BindingStrength.EXAMPLE || left.getStrength() != BindingStrength.EXAMPLE) && !Base.compareDeep(left.getValueSet(), right.getValueSet(), false) ) { vm(IssueSeverity.INFORMATION, "Example/preferred bindings differ at "+path+" using binding from "+comp.getLeft().getName(), path, comp.getMessages(), res.getMessages()); } subset.setBinding(left); - superset.setBinding(unionBindings(comp, res, path, left, right)); + superset.setBinding(unionBindings(comp, res, path, left, right, leftSrc, rightSrc)); } return true; } // if either of them are extensible/required, then it wins if (isPreferredOrExample(left)) { subset.setBinding(right); - superset.setBinding(unionBindings(comp, res, path, left, right)); + superset.setBinding(unionBindings(comp, res, path, left, right, leftSrc, rightSrc)); return true; } if (isPreferredOrExample(right)) { subset.setBinding(left); - superset.setBinding(unionBindings(comp, res, path, left, right)); + superset.setBinding(unionBindings(comp, res, path, left, right, leftSrc, rightSrc)); return true; } @@ -800,8 +801,8 @@ public class ProfileComparer extends CanonicalResourceComparer { return true; } else { // ok, now we compare the value sets. This may be unresolvable. - ValueSet lvs = resolveVS(comp.getLeft(), left.getValueSet(), session.getContextLeft()); - ValueSet rvs = resolveVS(comp.getRight(), right.getValueSet(), session.getContextRight()); + ValueSet lvs = resolveVS(comp.getLeft(), left.getValueSet(), leftSrc, session.getContextLeft()); + ValueSet rvs = resolveVS(comp.getRight(), right.getValueSet(), rightSrc, session.getContextRight()); if (lvs == null) { vm(IssueSeverity.ERROR, "Unable to resolve left value set "+left.getValueSet().toString()+" at "+path, path, comp.getMessages(), res.getMessages()); return true; @@ -885,8 +886,8 @@ public class ProfileComparer extends CanonicalResourceComparer { return result; } - private StructureDefinition resolveProfile(ProfileComparison comp, StructuralMatch res, String path, String url, String name, IWorkerContext ctxt) { - StructureDefinition sd = ctxt.fetchResource(StructureDefinition.class, url); + private StructureDefinition resolveProfile(ProfileComparison comp, StructuralMatch res, String path, String url, String name, IWorkerContext ctxt, Resource urlSource) { + StructureDefinition sd = ctxt.fetchResource(StructureDefinition.class, url, urlSource); if (sd == null) { ValidationMessage vm = vmI(IssueSeverity.WARNING, "Unable to resolve profile "+url+" in profile "+name, path); } @@ -897,7 +898,7 @@ public class ProfileComparer extends CanonicalResourceComparer { return binding.getStrength() == BindingStrength.EXAMPLE || binding.getStrength() == BindingStrength.PREFERRED; } - private ElementDefinitionBindingComponent unionBindings(ProfileComparison comp, StructuralMatch res, String path, ElementDefinitionBindingComponent left, ElementDefinitionBindingComponent right) throws FHIRFormatError, DefinitionException, IOException { + private ElementDefinitionBindingComponent unionBindings(ProfileComparison comp, StructuralMatch res, String path, ElementDefinitionBindingComponent left, ElementDefinitionBindingComponent right, Resource leftSrc, Resource rightSrc) throws FHIRFormatError, DefinitionException, IOException { ElementDefinitionBindingComponent union = new ElementDefinitionBindingComponent(); if (left.getStrength().compareTo(right.getStrength()) < 0) union.setStrength(left.getStrength()); @@ -907,8 +908,8 @@ public class ProfileComparer extends CanonicalResourceComparer { if (Base.compareDeep(left.getValueSet(), right.getValueSet(), false)) union.setValueSet(left.getValueSet()); else { - ValueSet lvs = resolveVS(comp.getLeft(), left.getValueSet(), session.getContextLeft()); - ValueSet rvs = resolveVS(comp.getRight(), right.getValueSet(), session.getContextRight()); + ValueSet lvs = resolveVS(comp.getLeft(), left.getValueSet(), leftSrc, session.getContextLeft()); + ValueSet rvs = resolveVS(comp.getRight(), right.getValueSet(), rightSrc, session.getContextRight()); if (lvs != null && rvs != null) { ValueSetComparison compP = (ValueSetComparison) session.compare(lvs, rvs); if (compP != null) { @@ -923,10 +924,10 @@ public class ProfileComparer extends CanonicalResourceComparer { return union; } - private ValueSet resolveVS(StructureDefinition ctxtLeft, String vsRef, IWorkerContext ctxt) { + private ValueSet resolveVS(StructureDefinition ctxtLeft, String vsRef, Resource src, IWorkerContext ctxt) { if (vsRef == null) return null; - return ctxt.fetchResource(ValueSet.class, vsRef); + return ctxt.fetchResource(ValueSet.class, vsRef, src); } public XhtmlNode renderStructure(ProfileComparison comp, String id, String prefix, String corePath) throws FHIRException, IOException { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfileUtilities.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfileUtilities.java index 9f6724cfe..b4f3c14c2 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfileUtilities.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfileUtilities.java @@ -58,7 +58,6 @@ import org.hl7.fhir.exceptions.FHIRFormatError; import org.hl7.fhir.r5.conformance.ProfileUtilities.SourcedChildDefinitions; import org.hl7.fhir.r5.conformance.ProfileUtilities.ProfileKnowledgeProvider.BindingResolution; import org.hl7.fhir.r5.context.IWorkerContext; -import org.hl7.fhir.r5.context.IWorkerContext.PackageVersion; import org.hl7.fhir.r5.context.IWorkerContext.ValidationResult; import org.hl7.fhir.r5.elementmodel.ObjectConverter; import org.hl7.fhir.r5.elementmodel.Property; @@ -474,7 +473,7 @@ public class ProfileUtilities extends TranslatingUtilities { } else if (element.getContentReference().contains("#")) { // external reference String ref = element.getContentReference(); - StructureDefinition sd = context.fetchResource(StructureDefinition.class, ref.substring(0, ref.indexOf("#"))); + StructureDefinition sd = context.fetchResource(StructureDefinition.class, ref.substring(0, ref.indexOf("#")), profile); if (sd == null) { throw new DefinitionException("unable to process contentReference '"+element.getContentReference()+"' on element '"+element.getId()+"'"); } @@ -578,7 +577,7 @@ public class ProfileUtilities extends TranslatingUtilities { return getChildList(profile, e.getContentReference().substring(1), null, diff); } else if (e.getContentReference().contains("#")) { String url = e.getContentReference().substring(0, e.getContentReference().indexOf("#")); - StructureDefinition sd = context.fetchResource(StructureDefinition.class, url); + StructureDefinition sd = context.fetchResource(StructureDefinition.class, url, profile); if (sd == null) { throw new DefinitionException("Unable to find Structure "+url); } @@ -722,7 +721,7 @@ public class ProfileUtilities extends TranslatingUtilities { // debug = true; // } processPaths("", derived.getSnapshot(), baseSnapshot, diff, baseCursor, diffCursor, baseSnapshot.getElement().size()-1, - derived.getDifferential().hasElement() ? derived.getDifferential().getElement().size()-1 : -1, url, webUrl, derived.present(), null, null, false, base.getUrl(), null, false, null, null, new ArrayList(), base); + derived.getDifferential().hasElement() ? derived.getDifferential().getElement().size()-1 : -1, url, webUrl, derived.present(), null, null, false, base.getUrl(), null, false, null, null, new ArrayList(), base, derived); checkGroupConstraints(derived); if (derived.getDerivation() == TypeDerivationRule.SPECIALIZATION) { for (ElementDefinition e : diff.getElement()) { @@ -824,7 +823,7 @@ public class ProfileUtilities extends TranslatingUtilities { for (ElementDefinition ed : derived.getSnapshot().getElement()) { for (TypeRefComponent t : ed.getType()) { for (UriType u : t.getProfile()) { - StructureDefinition sd = context.fetchResource(StructureDefinition.class, u.getValue()); + StructureDefinition sd = context.fetchResource(StructureDefinition.class, u.getValue(), derived); if (sd == null) { if (xver != null && xver.matchingUrl(u.getValue()) && xver.status(u.getValue()) == XVerExtensionStatus.Valid) { sd = xver.makeDefinition(u.getValue()); @@ -922,7 +921,7 @@ public class ProfileUtilities extends TranslatingUtilities { public void checkDifferentialBaseType(StructureDefinition derived) throws Error { if (derived.hasDifferential() && !derived.getDifferential().getElementFirstRep().getPath().contains(".") && !derived.getDifferential().getElementFirstRep().getType().isEmpty()) { - if (wantFixDifferentialFirstElementType && typeMatchesAncestor(derived.getDifferential().getElementFirstRep().getType(), derived.getBaseDefinition())) { + if (wantFixDifferentialFirstElementType && typeMatchesAncestor(derived.getDifferential().getElementFirstRep().getType(), derived.getBaseDefinition(), derived)) { derived.getDifferential().getElementFirstRep().getType().clear(); } else if (derived.getKind() != StructureDefinitionKind.LOGICAL) { throw new Error(context.formatMessage(I18nConstants.TYPE_ON_FIRST_DIFFERENTIAL_ELEMENT)); @@ -930,8 +929,8 @@ public class ProfileUtilities extends TranslatingUtilities { } } - private boolean typeMatchesAncestor(List type, String baseDefinition) { - StructureDefinition sd = context.fetchResource(StructureDefinition.class, baseDefinition); + private boolean typeMatchesAncestor(List type, String baseDefinition, Resource src) { + StructureDefinition sd = context.fetchResource(StructureDefinition.class, baseDefinition, src); return sd != null && type.size() == 1 && sd.getType().equals(type.get(0).getCode()); } @@ -1072,7 +1071,7 @@ public class ProfileUtilities extends TranslatingUtilities { if (sd.getUrl().equals(sdb.getUrl())) { return true; } - sd = context.fetchResource(StructureDefinition.class, sd.getBaseDefinition()); + sd = context.fetchResource(StructureDefinition.class, sd.getBaseDefinition(), sd); } return false; } @@ -1179,11 +1178,12 @@ public class ProfileUtilities extends TranslatingUtilities { /** * @param trimDifferential * @param srcSD + * @param derived * @throws DefinitionException, FHIRException * @throws Exception */ private ElementDefinition processPaths(String indent, StructureDefinitionSnapshotComponent result, StructureDefinitionSnapshotComponent base, StructureDefinitionDifferentialComponent differential, int baseCursor, int diffCursor, int baseLimit, - int diffLimit, String url, String webUrl, String profileName, String contextPathSrc, String contextPathDst, boolean trimDifferential, String contextName, String resultPathBase, boolean slicingDone, ElementDefinition slicer, String typeSlicingPath, List redirector, StructureDefinition srcSD) throws DefinitionException, FHIRException { + int diffLimit, String url, String webUrl, String profileName, String contextPathSrc, String contextPathDst, boolean trimDifferential, String contextName, String resultPathBase, boolean slicingDone, ElementDefinition slicer, String typeSlicingPath, List redirector, StructureDefinition srcSD, StructureDefinition derived) throws DefinitionException, FHIRException { if (debug) { System.out.println(indent+"PP @ "+resultPathBase+" / "+contextPathSrc+" : base = "+baseCursor+" to "+baseLimit+", diff = "+diffCursor+" to "+diffLimit+" (slicing = "+slicingDone+", k "+(redirector == null ? "null" : redirector.toString())+")"); } @@ -1218,7 +1218,7 @@ public class ProfileUtilities extends TranslatingUtilities { // well, the profile walks into this, so we need to as well // did we implicitly step into a new type? if (baseHasChildren(base, currentBase)) { // not a new type here - processPaths(indent+" ", result, base, differential, baseCursor+1, diffCursor, baseLimit, diffLimit, url, webUrl, profileName, contextPathSrc, contextPathDst, trimDifferential, contextName, resultPathBase, false, null, null, redirector, srcSD); + processPaths(indent+" ", result, base, differential, baseCursor+1, diffCursor, baseLimit, diffLimit, url, webUrl, profileName, contextPathSrc, contextPathDst, trimDifferential, contextName, resultPathBase, false, null, null, redirector, srcSD, derived); baseCursor = indexOfFirstNonChild(base, currentBase, baseCursor+1, baseLimit); } else { if (outcome.getType().size() == 0 && !outcome.hasContentReference()) { @@ -1253,27 +1253,27 @@ public class ProfileUtilities extends TranslatingUtilities { int nbl = nbc; while (nbl < base.getElement().size() && base.getElement().get(nbl).getPath().startsWith(tgt.getElement().getPath()+".")) nbl++; - processPaths(indent+" ", result, base, differential, nbc, start - 1, nbl-1, diffCursor - 1, url, webUrl, profileName, tgt.getElement().getPath(), diffMatches.get(0).getPath(), trimDifferential, contextName, resultPathBase, false, null, null, redirectorStack(redirector, outcome, cpath), tgt.getSource()); + processPaths(indent+" ", result, base, differential, nbc, start - 1, nbl-1, diffCursor - 1, url, webUrl, profileName, tgt.getElement().getPath(), diffMatches.get(0).getPath(), trimDifferential, contextName, resultPathBase, false, null, null, redirectorStack(redirector, outcome, cpath), tgt.getSource(), derived); } else { int nbc = base.getElement().indexOf(tgt.getElement())+1; int nbl = nbc; while (nbl < base.getElement().size() && base.getElement().get(nbl).getPath().startsWith(tgt.getElement().getPath()+".")) nbl++; System.out.println("Test!"); - processPaths(indent+" ", result, base, differential, nbc, start, nbl-1, diffCursor-1, url, webUrl, profileName, tgt.getElement().getPath(), outcome.getPath(), trimDifferential, contextName, resultPathBase, false, null, null, redirectorStack(redirector, outcome, cpath), srcSD); + processPaths(indent+" ", result, base, differential, nbc, start, nbl-1, diffCursor-1, url, webUrl, profileName, tgt.getElement().getPath(), outcome.getPath(), trimDifferential, contextName, resultPathBase, false, null, null, redirectorStack(redirector, outcome, cpath), srcSD, derived); } } else { - StructureDefinition dt = outcome.getType().size() > 1 ? context.fetchTypeDefinition("Element") : getProfileForDataType(outcome.getType().get(0), webUrl); + StructureDefinition dt = outcome.getType().size() > 1 ? context.fetchTypeDefinition("Element") : getProfileForDataType(outcome.getType().get(0), webUrl, srcSD); if (dt == null) { throw new DefinitionException(context.formatMessage(I18nConstants.UNKNOWN_TYPE__AT_, outcome.getType().get(0), cpath)); } contextName = dt.getUrl(); if (redirector == null || redirector.isEmpty()) { processPaths(indent+" ", result, dt.getSnapshot(), differential, 1 /* starting again on the data type, but skip the root */, start, dt.getSnapshot().getElement().size()-1, - diffCursor-1, url, getWebUrl(dt, webUrl, indent), profileName, cpath, outcome.getPath(), trimDifferential, contextName, resultPathBase, false, null, null, redirector, srcSD); + diffCursor-1, url, getWebUrl(dt, webUrl, indent), profileName, cpath, outcome.getPath(), trimDifferential, contextName, resultPathBase, false, null, null, redirector, srcSD, derived); } else { processPaths(indent+" ", result, dt.getSnapshot(), differential, 1 /* starting again on the data type, but skip the root */, start, dt.getSnapshot().getElement().size()-1, - diffCursor-1, url, getWebUrl(dt, webUrl, indent), profileName, cpath, outcome.getPath(), trimDifferential, contextName, resultPathBase, false, null, null, redirectorStack(redirector, currentBase, cpath), srcSD); + diffCursor-1, url, getWebUrl(dt, webUrl, indent), profileName, cpath, outcome.getPath(), trimDifferential, contextName, resultPathBase, false, null, null, redirectorStack(redirector, currentBase, cpath), srcSD, derived); } } } @@ -1294,7 +1294,7 @@ public class ProfileUtilities extends TranslatingUtilities { } else if (diffMatches.get(0).hasType() && diffMatches.get(0).getType().size() == 1 && diffMatches.get(0).getType().get(0).hasProfile() && !"Reference".equals(diffMatches.get(0).getType().get(0).getWorkingCode())) { CanonicalType p = diffMatches.get(0).getType().get(0).getProfile().get(0); - StructureDefinition sd = context.fetchResource(StructureDefinition.class, p.getValue()); + StructureDefinition sd = context.fetchResource(StructureDefinition.class, p.getValue(), derived); if (sd == null && xver != null && xver.matchingUrl(p.getValue())) { switch (xver.status(p.getValue())) { case BadVersion: throw new FHIRException("Reference to invalid version in extension url "+p.getValue()); @@ -1316,7 +1316,7 @@ public class ProfileUtilities extends TranslatingUtilities { throw new FHIRException(context.formatMessage(I18nConstants.ATTEMPT_TO_USE_A_SNAPSHOT_ON_PROFILE__AS__BEFORE_IT_IS_GENERATED, sd.getUrl(), "Source for first element")); } } else if (!sd.hasSnapshot()) { - StructureDefinition sdb = context.fetchResource(StructureDefinition.class, sd.getBaseDefinition()); + StructureDefinition sdb = context.fetchResource(StructureDefinition.class, sd.getBaseDefinition(), sd); if (sdb == null) throw new DefinitionException(context.formatMessage(I18nConstants.UNABLE_TO_FIND_BASE__FOR_, sd.getBaseDefinition(), sd.getUrl())); checkNotGenerating(sdb, "an extension base"); @@ -1362,7 +1362,7 @@ public class ProfileUtilities extends TranslatingUtilities { } } } - updateFromDefinition(outcome, diffMatches.get(0), profileName, trimDifferential, url, srcSD); + updateFromDefinition(outcome, diffMatches.get(0), profileName, trimDifferential, url, srcSD, derived); removeStatusExtensions(outcome); // if (outcome.getPath().endsWith("[x]") && outcome.getType().size() == 1 && !outcome.getType().get(0).getCode().equals("*") && !diffMatches.get(0).hasSlicing()) // if the base profile allows multiple types, but the profile only allows one, rename it // outcome.setPath(outcome.getPath().substring(0, outcome.getPath().length()-3)+Utilities.capitalize(outcome.getType().get(0).getCode())); @@ -1415,21 +1415,21 @@ public class ProfileUtilities extends TranslatingUtilities { int nbl = nbc; while (nbl < base.getElement().size() && base.getElement().get(nbl).getPath().startsWith(tgt.getElement().getPath()+".")) nbl++; - processPaths(indent+" ", result, base, differential, nbc, start - 1, nbl-1, diffCursor - 1, url, webUrl, profileName, tgt.getElement().getPath(), diffMatches.get(0).getPath(), trimDifferential, contextName, resultPathBase, false, null, null, redirectorStack(redirector, outcome, cpath), tgt.getSource()); + processPaths(indent+" ", result, base, differential, nbc, start - 1, nbl-1, diffCursor - 1, url, webUrl, profileName, tgt.getElement().getPath(), diffMatches.get(0).getPath(), trimDifferential, contextName, resultPathBase, false, null, null, redirectorStack(redirector, outcome, cpath), tgt.getSource(), derived); } else { int nbc = base.getElement().indexOf(tgt.getElement())+1; int nbl = nbc; while (nbl < base.getElement().size() && base.getElement().get(nbl).getPath().startsWith(tgt.getElement().getPath()+".")) nbl++; - processPaths(indent+" ", result, base, differential, nbc, start - 1, nbl-1, diffCursor - 1, url, webUrl, profileName, tgt.getElement().getPath(), diffMatches.get(0).getPath(), trimDifferential, contextName, resultPathBase, false, null, null, redirectorStack(redirector, outcome, cpath), srcSD); + processPaths(indent+" ", result, base, differential, nbc, start - 1, nbl-1, diffCursor - 1, url, webUrl, profileName, tgt.getElement().getPath(), diffMatches.get(0).getPath(), trimDifferential, contextName, resultPathBase, false, null, null, redirectorStack(redirector, outcome, cpath), srcSD, derived); } } else { - StructureDefinition dt = outcome.getType().size() == 1 ? getProfileForDataType(outcome.getType().get(0), webUrl) : getProfileForDataType("Element"); + StructureDefinition dt = outcome.getType().size() == 1 ? getProfileForDataType(outcome.getType().get(0), webUrl, derived) : getProfileForDataType("Element"); if (dt == null) throw new DefinitionException(context.formatMessage(I18nConstants._HAS_CHILDREN__FOR_TYPE__IN_PROFILE__BUT_CANT_FIND_TYPE, diffMatches.isEmpty() ? "??" : diffMatches.get(0).getPath(), differential.getElement().get(diffCursor).getPath(), typeCode(outcome.getType()), profileName)); contextName = dt.getUrl(); processPaths(indent+" ", result, dt.getSnapshot(), differential, 1 /* starting again on the data type, but skip the root */, start, dt.getSnapshot().getElement().size()-1, - diffCursor - 1, url, getWebUrl(dt, webUrl, indent), profileName+pathTail(diffMatches, 0), diffMatches.get(0).getPath(), outcome.getPath(), trimDifferential, contextName, resultPathBase, false, null, null, new ArrayList(), srcSD); + diffCursor - 1, url, getWebUrl(dt, webUrl, indent), profileName+pathTail(diffMatches, 0), diffMatches.get(0).getPath(), outcome.getPath(), trimDifferential, contextName, resultPathBase, false, null, null, new ArrayList(), srcSD, derived); } } } @@ -1515,7 +1515,7 @@ public class ProfileUtilities extends TranslatingUtilities { // ok passed the checks. // copy the root diff, and then process any children it has ElementDefinition e = processPaths(indent+" ", result, base, differential, baseCursor, ndc, nbl, ndl, url, webUrl, profileName+pathTail(diffMatches, 0), contextPathSrc, contextPathDst, - trimDifferential, contextName, resultPathBase, true, null, null, redirector, srcSD); + trimDifferential, contextName, resultPathBase, true, null, null, redirector, srcSD, derived); if (e==null) throw new FHIRException(context.formatMessage(I18nConstants.DID_NOT_FIND_TYPE_ROOT_, diffMatches.get(0).getPath())); // now set up slicing on the e (cause it was wiped by what we called. @@ -1541,7 +1541,7 @@ public class ProfileUtilities extends TranslatingUtilities { } ndc = differential.getElement().indexOf(diffMatches.get(i)); ndl = findEndOfElement(differential, ndc); - ElementDefinition typeSliceElement = processPaths(indent+" ", result, base, differential, baseCursor, ndc, nbl, ndl, url, webUrl, profileName+pathTail(diffMatches, i), contextPathSrc, contextPathDst, trimDifferential, contextName, resultPathBase, true, e, null, redirector, srcSD); + ElementDefinition typeSliceElement = processPaths(indent+" ", result, base, differential, baseCursor, ndc, nbl, ndl, url, webUrl, profileName+pathTail(diffMatches, i), contextPathSrc, contextPathDst, trimDifferential, contextName, resultPathBase, true, e, null, redirector, srcSD, derived); if (typeList.size() > start+1) { typeSliceElement.setMin(0); } @@ -1606,7 +1606,7 @@ public class ProfileUtilities extends TranslatingUtilities { int ndc = differential.getElement().indexOf(diffMatches.get(0)); int ndl = findEndOfElement(differential, ndc); ElementDefinition e = processPaths(indent+" ", result, base, differential, baseCursor, ndc, nbl, ndl, url, webUrl, profileName+pathTail(diffMatches, 0), contextPathSrc, contextPathDst, - trimDifferential, contextName, resultPathBase, true, null, null, redirector, srcSD); + trimDifferential, contextName, resultPathBase, true, null, null, redirector, srcSD, derived); if (e==null) throw new FHIRException(context.formatMessage(I18nConstants.DID_NOT_FIND_SINGLE_SLICE_, diffMatches.get(0).getPath())); e.setSlicing(diffMatches.get(0).getSlicing()); @@ -1629,7 +1629,7 @@ public class ProfileUtilities extends TranslatingUtilities { // differential - if the first one in the list has a name, we'll process it. Else we'll treat it as the base definition of the slice. if (!diffMatches.get(0).hasSliceName()) { - updateFromDefinition(outcome, diffMatches.get(0), profileName, trimDifferential, url, srcSD); + updateFromDefinition(outcome, diffMatches.get(0), profileName, trimDifferential, url, srcSD, derived); removeStatusExtensions(outcome); if (!outcome.hasContentReference() && !outcome.hasType()) { throw new DefinitionException(context.formatMessage(I18nConstants.NOT_DONE_YET)); @@ -1638,7 +1638,7 @@ public class ProfileUtilities extends TranslatingUtilities { if (baseHasChildren(base, currentBase)) { // not a new type here throw new Error("This situation is not yet handled (constrain slicing to 1..1 and fix base slice for inline structure - please report issue to grahame@fhir.org along with a test case that reproduces this error (@ "+cpath+" | "+currentBase.getPath()+")"); } else { - StructureDefinition dt = getTypeForElement(differential, diffCursor, profileName, diffMatches, outcome, webUrl); + StructureDefinition dt = getTypeForElement(differential, diffCursor, profileName, diffMatches, outcome, webUrl, srcSD); contextName = dt.getUrl(); diffCursor++; start = diffCursor; @@ -1646,7 +1646,7 @@ public class ProfileUtilities extends TranslatingUtilities { diffCursor++; diffCursor--; processPaths(indent+" ", result, dt.getSnapshot(), differential, 1 /* starting again on the data type, but skip the root */, start, dt.getSnapshot().getElement().size()-1, - diffCursor, url, getWebUrl(dt, webUrl, indent), profileName, cpath, outcome.getPath(), trimDifferential, contextName, resultPathBase, false, null, null, redirector, srcSD); + diffCursor, url, getWebUrl(dt, webUrl, indent), profileName, cpath, outcome.getPath(), trimDifferential, contextName, resultPathBase, false, null, null, redirector, srcSD, derived); } } start++; @@ -1668,7 +1668,7 @@ public class ProfileUtilities extends TranslatingUtilities { continue; }*/ // now we process the base scope repeatedly for each instance of the item in the differential list - processPaths(indent+" ", result, base, differential, baseCursor, ndc, nbl, ndl, url, webUrl, profileName+pathTail(diffMatches, i), contextPathSrc, contextPathDst, trimDifferential, contextName, resultPathBase, true, slicerElement, null, redirector, srcSD); + processPaths(indent+" ", result, base, differential, baseCursor, ndc, nbl, ndl, url, webUrl, profileName+pathTail(diffMatches, i), contextPathSrc, contextPathDst, trimDifferential, contextName, resultPathBase, true, slicerElement, null, redirector, srcSD, derived); } // ok, done with that - next in the base list baseCursor = nbl+1; @@ -1701,10 +1701,10 @@ public class ProfileUtilities extends TranslatingUtilities { // the profile walks into this, so we need to as well // did we implicitly step into a new type? if (baseHasChildren(base, currentBase)) { // not a new type here - processPaths(indent+" ", result, base, differential, baseCursor+1, diffCursor, baseLimit, diffLimit, url, webUrl, profileName, contextPathSrc, contextPathDst, trimDifferential, contextName, resultPathBase, false, null, null, redirector, srcSD); + processPaths(indent+" ", result, base, differential, baseCursor+1, diffCursor, baseLimit, diffLimit, url, webUrl, profileName, contextPathSrc, contextPathDst, trimDifferential, contextName, resultPathBase, false, null, null, redirector, srcSD, derived); baseCursor = indexOfFirstNonChild(base, currentBase, baseCursor, baseLimit); } else { - StructureDefinition dt = getTypeForElement(differential, diffCursor, profileName, diffMatches, outcome, webUrl); + StructureDefinition dt = getTypeForElement(differential, diffCursor, profileName, diffMatches, outcome, webUrl, srcSD); contextName = dt.getUrl(); int start = diffCursor; if (differential.getElement().get(diffCursor).getPath().equals(cpath)) { @@ -1715,7 +1715,7 @@ public class ProfileUtilities extends TranslatingUtilities { } if (diffCursor > start) { processPaths(indent+" ", result, dt.getSnapshot(), differential, 1 /* starting again on the data type, but skip the root */, start, dt.getSnapshot().getElement().size()-1, - diffCursor-1, url, getWebUrl(dt, webUrl, indent), profileName, cpath, outcome.getPath(), trimDifferential, contextName, resultPathBase, false, null, null, redirector, srcSD); + diffCursor-1, url, getWebUrl(dt, webUrl, indent), profileName, cpath, outcome.getPath(), trimDifferential, contextName, resultPathBase, false, null, null, redirector, srcSD, derived); } } baseCursor++; @@ -1811,7 +1811,7 @@ public class ProfileUtilities extends TranslatingUtilities { // ok passed the checks. // copy the root diff, and then process any children it has ElementDefinition e = processPaths(indent+" ", result, base, differential, baseCursor, ndc, nbl, ndl, url, webUrl, profileName+pathTail(diffMatches, 0), contextPathSrc, contextPathDst, - trimDifferential, contextName, resultPathBase, true, null, cpath, redirector, srcSD); + trimDifferential, contextName, resultPathBase, true, null, cpath, redirector, srcSD, derived); if (e==null) throw new FHIRException(context.formatMessage(I18nConstants.DID_NOT_FIND_TYPE_ROOT_, diffMatches.get(0).getPath())); // now set up slicing on the e (cause it was wiped by what we called. @@ -1844,7 +1844,7 @@ public class ProfileUtilities extends TranslatingUtilities { sEnd = bs.end; bs.handled = true; } - processPaths(indent+" ", result, base, differential, sStart, ndc, sEnd, ndl, url, webUrl, profileName+pathTail(diffMatches, i), contextPathSrc, contextPathDst, trimDifferential, contextName, resultPathBase, true, e, cpath, redirector, srcSD); + processPaths(indent+" ", result, base, differential, sStart, ndc, sEnd, ndl, url, webUrl, profileName+pathTail(diffMatches, i), contextPathSrc, contextPathDst, trimDifferential, contextName, resultPathBase, true, e, cpath, redirector, srcSD, derived); } if (elementToRemove != null) { differential.getElement().remove(elementToRemove); @@ -1863,7 +1863,7 @@ public class ProfileUtilities extends TranslatingUtilities { // ok we gimme up a fake differential that says nothing, and run that against the slice. StructureDefinitionDifferentialComponent fakeDiff = new StructureDefinitionDifferentialComponent(); fakeDiff.getElementFirstRep().setPath(bs.defn.getPath()); - processPaths(indent+" ", result, base, fakeDiff, bs.start, 0, bs.end, 0, url, webUrl, profileName+tail(bs.defn.getPath()), contextPathSrc, contextPathDst, trimDifferential, contextName, resultPathBase, true, e, cpath, redirector, srcSD); + processPaths(indent+" ", result, base, fakeDiff, bs.start, 0, bs.end, 0, url, webUrl, profileName+tail(bs.defn.getPath()), contextPathSrc, contextPathDst, trimDifferential, contextName, resultPathBase, true, e, cpath, redirector, srcSD, derived); } } @@ -1893,7 +1893,7 @@ public class ProfileUtilities extends TranslatingUtilities { updateFromBase(outcome, currentBase, srcSD.getUrl()); if (diffMatches.get(0).hasSlicing() || !diffMatches.get(0).hasSliceName()) { updateFromSlicing(outcome.getSlicing(), diffMatches.get(0).getSlicing()); - updateFromDefinition(outcome, diffMatches.get(0), profileName, closed, url, srcSD); // if there's no slice, we don't want to update the unsliced description + updateFromDefinition(outcome, diffMatches.get(0), profileName, closed, url, srcSD, derived); // if there's no slice, we don't want to update the unsliced description removeStatusExtensions(outcome); } else if (!diffMatches.get(0).hasSliceName()) { diffMatches.get(0).setUserData(GENERATED_IN_SNAPSHOT, outcome); // because of updateFromDefinition isn't called @@ -1913,7 +1913,7 @@ public class ProfileUtilities extends TranslatingUtilities { if (base.getElement().get(baseCursor).getType().size() != 1) { throw new Error(context.formatMessage(I18nConstants.DIFFERENTIAL_WALKS_INTO____BUT_THE_BASE_DOES_NOT_AND_THERE_IS_NOT_A_SINGLE_FIXED_TYPE_THE_TYPE_IS__THIS_IS_NOT_HANDLED_YET, cpath, diffMatches.get(0).toString(), base.getElement().get(baseCursor).typeSummary())); } - StructureDefinition dt = getProfileForDataType(base.getElement().get(baseCursor).getType().get(0), webUrl); + StructureDefinition dt = getProfileForDataType(base.getElement().get(baseCursor).getType().get(0), webUrl, srcSD); if (dt == null) { throw new DefinitionException(context.formatMessage(I18nConstants.UNKNOWN_TYPE__AT_, outcome.getType().get(0), diffMatches.get(0).getPath())); } @@ -1921,10 +1921,10 @@ public class ProfileUtilities extends TranslatingUtilities { while (differential.getElement().size() > diffCursor && pathStartsWith(differential.getElement().get(diffCursor).getPath(), cpath+".")) diffCursor++; processPaths(indent+" ", result, dt.getSnapshot(), differential, 1, ndc, dt.getSnapshot().getElement().size()-1, ndl, - url, getWebUrl(dt, webUrl, indent), profileName, cpath, outcome.getPath(), trimDifferential, contextName, resultPathBase, false, null, null, redirector, srcSD); + url, getWebUrl(dt, webUrl, indent), profileName, cpath, outcome.getPath(), trimDifferential, contextName, resultPathBase, false, null, null, redirector, srcSD, derived); } else { processPaths(indent+" ", result, base, differential, baseCursor+1, ndc, nbl, ndl, - url, webUrl, profileName+pathTail(diffMatches, 0), contextPathSrc, contextPathDst, trimDifferential, contextName, resultPathBase, false, null, null, null, srcSD); + url, webUrl, profileName+pathTail(diffMatches, 0), contextPathSrc, contextPathDst, trimDifferential, contextName, resultPathBase, false, null, null, null, srcSD, derived); } // throw new Error("Not done yet"); // } else if (currentBase.getType().get(0).getCode().equals("BackboneElement") && diffMatches.size() > 0 && diffMatches.get(0).hasSliceName()) { @@ -1955,7 +1955,7 @@ public class ProfileUtilities extends TranslatingUtilities { int ndc = differential.getElement().indexOf(diffMatches.get(diffpos)); int ndl = findEndOfElement(differential, ndc); // now we process the base scope repeatedly for each instance of the item in the differential list - processPaths(indent+" ", result, base, differential, baseCursor, ndc, nbl, ndl, url, webUrl, profileName+pathTail(diffMatches, diffpos), contextPathSrc, contextPathDst, closed, contextName, resultPathBase, true, null, null, redirector, srcSD); + processPaths(indent+" ", result, base, differential, baseCursor, ndc, nbl, ndl, url, webUrl, profileName+pathTail(diffMatches, diffpos), contextPathSrc, contextPathDst, closed, contextName, resultPathBase, true, null, null, redirector, srcSD, derived); // ok, done with that - now set the cursors for if this is the end baseCursor = nbl; diffCursor = ndl+1; @@ -2006,7 +2006,7 @@ public class ProfileUtilities extends TranslatingUtilities { if (!outcome.getPath().startsWith(resultPathBase)) throw new DefinitionException(context.formatMessage(I18nConstants.ADDING_WRONG_PATH)); result.getElement().add(outcome); - updateFromDefinition(outcome, diffItem, profileName, trimDifferential, url, srcSD); + updateFromDefinition(outcome, diffItem, profileName, trimDifferential, url, srcSD, derived); removeStatusExtensions(outcome); // --- LM Added this diffCursor = differential.getElement().indexOf(diffItem)+1; @@ -2028,10 +2028,10 @@ public class ProfileUtilities extends TranslatingUtilities { while (differential.getElement().size() > diffCursor && pathStartsWith(differential.getElement().get(diffCursor).getPath(), diffMatches.get(0).getPath()+".")) diffCursor++; processPaths(indent+" ", result, base, differential, baseStart, start-1, baseMax-1, - diffCursor - 1, url, webUrl, profileName+pathTail(diffMatches, 0), base.getElement().get(0).getPath(), base.getElement().get(0).getPath(), trimDifferential, contextName, resultPathBase, false, null, null, redirector, srcSD); + diffCursor - 1, url, webUrl, profileName+pathTail(diffMatches, 0), base.getElement().get(0).getPath(), base.getElement().get(0).getPath(), trimDifferential, contextName, resultPathBase, false, null, null, redirector, srcSD, derived); } else { - StructureDefinition dt = getProfileForDataType(outcome.getType().get(0), webUrl); + StructureDefinition dt = getProfileForDataType(outcome.getType().get(0), webUrl, derived); // if (t.getCode().equals("Extension") && t.hasProfile() && !t.getProfile().contains(":")) { // lloydfix dt = // } @@ -2042,7 +2042,7 @@ public class ProfileUtilities extends TranslatingUtilities { while (differential.getElement().size() > diffCursor && pathStartsWith(differential.getElement().get(diffCursor).getPath(), diffMatches.get(0).getPath()+".")) diffCursor++; processPaths(indent+" ", result, dt.getSnapshot(), differential, 1 /* starting again on the data type, but skip the root */, start-1, dt.getSnapshot().getElement().size()-1, - diffCursor - 1, url, getWebUrl(dt, webUrl, indent), profileName+pathTail(diffMatches, 0), diffMatches.get(0).getPath(), outcome.getPath(), trimDifferential, contextName, resultPathBase, false, null, null, redirector, srcSD); + diffCursor - 1, url, getWebUrl(dt, webUrl, indent), profileName+pathTail(diffMatches, 0), diffMatches.get(0).getPath(), outcome.getPath(), trimDifferential, contextName, resultPathBase, false, null, null, redirector, srcSD, derived); } } } @@ -2092,7 +2092,7 @@ public class ProfileUtilities extends TranslatingUtilities { } public StructureDefinition getTypeForElement(StructureDefinitionDifferentialComponent differential, int diffCursor, String profileName, - List diffMatches, ElementDefinition outcome, String webUrl) { + List diffMatches, ElementDefinition outcome, String webUrl, Resource srcSD) { if (outcome.getType().size() == 0) { if (outcome.hasContentReference()) { throw new Error(context.formatMessage(I18nConstants.UNABLE_TO_RESOLVE_CONTENT_REFERENCE_IN_THIS_CONTEXT, outcome.getContentReference(), outcome.getId(), outcome.getPath())); @@ -2106,7 +2106,7 @@ public class ProfileUtilities extends TranslatingUtilities { throw new DefinitionException(context.formatMessage(I18nConstants._HAS_CHILDREN__AND_MULTIPLE_TYPES__IN_PROFILE_, diffMatches.get(0).getPath(), differential.getElement().get(diffCursor).getPath(), typeCode(outcome.getType()), profileName)); } } - StructureDefinition dt = getProfileForDataType(outcome.getType().get(0), webUrl); + StructureDefinition dt = getProfileForDataType(outcome.getType().get(0), webUrl, srcSD); if (dt == null) throw new DefinitionException(context.formatMessage(I18nConstants.UNKNOWN_TYPE__AT_, outcome.getType().get(0), diffMatches.get(0).getPath())); return dt; @@ -2143,7 +2143,7 @@ public class ProfileUtilities extends TranslatingUtilities { } } } - sd = context.fetchResource(StructureDefinition.class, sd.getBaseDefinition()); + sd = context.fetchResource(StructureDefinition.class, sd.getBaseDefinition(), sd); } return false; } @@ -2580,10 +2580,10 @@ public class ProfileUtilities extends TranslatingUtilities { return s; } - private StructureDefinition getProfileForDataType(TypeRefComponent type, String webUrl) { + private StructureDefinition getProfileForDataType(TypeRefComponent type, String webUrl, Resource src) { StructureDefinition sd = null; if (type.hasProfile()) { - sd = context.fetchResource(StructureDefinition.class, type.getProfile().get(0).getValue()); + sd = context.fetchResource(StructureDefinition.class, type.getProfile().get(0).getValue(), src); if (sd == null) { if (xver != null && xver.matchingUrl(type.getProfile().get(0).getValue()) && xver.status(type.getProfile().get(0).getValue()) == XVerExtensionStatus.Valid) { sd = xver.makeDefinition(type.getProfile().get(0).getValue()); @@ -2974,7 +2974,7 @@ public class ProfileUtilities extends TranslatingUtilities { return true; } - private void updateFromDefinition(ElementDefinition dest, ElementDefinition source, String pn, boolean trimDifferential, String purl, StructureDefinition srcSD) throws DefinitionException, FHIRException { + private void updateFromDefinition(ElementDefinition dest, ElementDefinition source, String pn, boolean trimDifferential, String purl, StructureDefinition srcSD, StructureDefinition derivedSrc) throws DefinitionException, FHIRException { source.setUserData(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 @@ -2992,9 +2992,9 @@ public class ProfileUtilities extends TranslatingUtilities { // Before applying changes, apply them to what's in the profile StructureDefinition profile = null; if (base.hasSliceName()) - profile = base.getType().size() == 1 && base.getTypeFirstRep().hasProfile() ? context.fetchResource(StructureDefinition.class, base.getTypeFirstRep().getProfile().get(0).getValue()) : null; + profile = base.getType().size() == 1 && base.getTypeFirstRep().hasProfile() ? context.fetchResource(StructureDefinition.class, base.getTypeFirstRep().getProfile().get(0).getValue(), srcSD) : null; if (profile==null) - profile = source.getType().size() == 1 && source.getTypeFirstRep().hasProfile() ? context.fetchResource(StructureDefinition.class, source.getTypeFirstRep().getProfile().get(0).getValue()) : null; + profile = source.getType().size() == 1 && source.getTypeFirstRep().hasProfile() ? context.fetchResource(StructureDefinition.class, source.getTypeFirstRep().getProfile().get(0).getValue(), derivedSrc) : null; if (profile != null) { ElementDefinition e = profile.getSnapshot().getElement().get(0); String webroot = profile.getUserString("webroot"); @@ -3208,8 +3208,8 @@ public class ProfileUtilities extends TranslatingUtilities { messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+derived.getPath(), "illegal attempt to change the binding on "+derived.getPath()+" from "+base.getBinding().getStrength().toCode()+" to "+derived.getBinding().getStrength().toCode(), ValidationMessage.IssueSeverity.ERROR)); // throw new DefinitionException("StructureDefinition "+pn+" at "+derived.getPath()+": illegal attempt to change a binding from "+base.getBinding().getStrength().toCode()+" to "+derived.getBinding().getStrength().toCode()); else if (base.hasBinding() && derived.hasBinding() && base.getBinding().getStrength() == BindingStrength.REQUIRED && base.getBinding().hasValueSet() && derived.getBinding().hasValueSet()) { - ValueSet baseVs = context.fetchResource(ValueSet.class, base.getBinding().getValueSet()); - ValueSet contextVs = context.fetchResource(ValueSet.class, derived.getBinding().getValueSet()); + ValueSet baseVs = context.fetchResource(ValueSet.class, base.getBinding().getValueSet(), srcSD); + ValueSet contextVs = context.fetchResource(ValueSet.class, derived.getBinding().getValueSet(), derivedSrc); if (baseVs == null) { messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+base.getPath(), "Binding "+base.getBinding().getValueSet()+" could not be located", ValidationMessage.IssueSeverity.WARNING)); } else if (contextVs == null) { @@ -3266,7 +3266,7 @@ public class ProfileUtilities extends TranslatingUtilities { if (!Base.compareDeep(derived.getType(), base.getType(), false)) { if (base.hasType()) { for (TypeRefComponent ts : derived.getType()) { - checkTypeDerivation(purl, srcSD, base, derived, ts); + checkTypeDerivation(purl, derivedSrc, base, derived, ts); } } base.getType().clear(); @@ -3338,7 +3338,7 @@ public class ProfileUtilities extends TranslatingUtilities { // finally, we copy any extensions from source to dest for (Extension ex : derived.getExtension()) { - StructureDefinition sd = context.fetchResource(StructureDefinition.class, ex.getUrl()); + StructureDefinition sd = context.fetchResource(StructureDefinition.class, ex.getUrl(), derivedSrc); if (sd == null || sd.getSnapshot() == null || sd.getSnapshot().getElementFirstRep().getMax().equals("1")) { ToolingExtensions.removeExtension(dest, ex.getUrl()); } @@ -3369,7 +3369,7 @@ public class ProfileUtilities extends TranslatingUtilities { StructureDefinition sdb = context.fetchTypeDefinition(t); while (sdb != null && !ok) { ok = sdb.getType().equals(sdt.getType()); - sdb = context.fetchResource(StructureDefinition.class, sdb.getBaseDefinition()); + sdb = context.fetchResource(StructureDefinition.class, sdb.getBaseDefinition(), sdb); } } } @@ -3616,7 +3616,7 @@ public class ProfileUtilities extends TranslatingUtilities { if (!child.getPath().endsWith(".id")) { List sdl = new ArrayList<>(); sdl.add(ed); - genElement(defFile == null ? "" : defFile+"-definitions.html#extension.", gen, r.getSubRows(), child, ed.getSnapshot().getElement(), sdl, true, defFile, true, full, corePath, imagePath, true, false, false, false, null, false, rc, ""); + genElement(defFile == null ? "" : defFile+"-definitions.html#extension.", gen, r.getSubRows(), child, ed.getSnapshot().getElement(), sdl, true, defFile, true, full, corePath, imagePath, true, false, false, false, null, false, rc, "", ed); } } else if (deep) { List children = new ArrayList(); @@ -3729,7 +3729,7 @@ public class ProfileUtilities extends TranslatingUtilities { List types = e.getType(); if (!e.hasType()) { if (root) { // we'll use base instead of types then - StructureDefinition bsd = profile == null ? null : context.fetchResource(StructureDefinition.class, profile.getBaseDefinition()); + StructureDefinition bsd = profile == null ? null : context.fetchResource(StructureDefinition.class, profile.getBaseDefinition(), profile); if (bsd != null) { if (bsd.hasUserData("path")) { c.getPieces().add(gen.new Piece(Utilities.isAbsoluteUrl(bsd.getUserString("path")) ? bsd.getUserString("path") : imagePath +bsd.getUserString("path"), bsd.getName(), null)); @@ -3780,7 +3780,7 @@ public class ProfileUtilities extends TranslatingUtilities { tfirst = false; else c.addPiece(gen.new Piece(null, " | ", null)); - genTargetLink(gen, profileBaseFileName, corePath, c, t, u.getValue()); + genTargetLink(gen, profileBaseFileName, corePath, c, t, u.getValue(), null); if (!mustSupportMode && isMustSupport(u) && e.getMustSupport()) { c.addPiece(gen.new Piece(null, " ", null)); c.addStyledText(translate("sd.table", "This target must be supported"), "S", "white", "red", null, false); @@ -3863,9 +3863,9 @@ public class ProfileUtilities extends TranslatingUtilities { return Utilities.isAbsoluteUrl(url) ? url : prefix + url; } - public void genTargetLink(HierarchicalTableGenerator gen, String profileBaseFileName, String corePath, Cell c, TypeRefComponent t, String u) { + public void genTargetLink(HierarchicalTableGenerator gen, String profileBaseFileName, String corePath, Cell c, TypeRefComponent t, String u, Resource src) { if (u.startsWith("http://hl7.org/fhir/StructureDefinition/")) { - StructureDefinition sd = context.fetchResource(StructureDefinition.class, u); + StructureDefinition sd = context.fetchResource(StructureDefinition.class, u, src); if (sd != null) { String disp = sd.hasTitle() ? sd.getTitle() : sd.getName(); c.addPiece(checkForNoChange(t, gen.new Piece(checkPrepend(corePath, sd.getUserString("path")), disp, null))); @@ -3874,7 +3874,7 @@ public class ProfileUtilities extends TranslatingUtilities { c.addPiece(checkForNoChange(t, gen.new Piece(pkp.getLinkFor(corePath, rn), rn, null))); } } else if (Utilities.isAbsoluteUrl(u)) { - StructureDefinition sd = context.fetchResource(StructureDefinition.class, u); + StructureDefinition sd = context.fetchResource(StructureDefinition.class, u, src); if (sd != null && pkp != null) { String disp = sd.hasTitle() ? sd.getTitle() : sd.getName(); String ref = pkp.getLinkForProfile(null, sd.getUrl()); @@ -3949,7 +3949,7 @@ public class ProfileUtilities extends TranslatingUtilities { url = source.getUrl(); } if (!url.equals(source.getUrl())) { - source = context.fetchResource(StructureDefinition.class, url); + source = context.fetchResource(StructureDefinition.class, url, source); if (source == null) { throw new FHIRException("Unable to resolve StructureDefinition "+url+" resolving content reference "+contentReference); } @@ -3973,7 +3973,7 @@ public class ProfileUtilities extends TranslatingUtilities { String url = contentReference.substring(0, contentReference.indexOf("#")); contentReference = contentReference.substring(contentReference.indexOf("#")); if (!url.equals(source.getUrl())){ - source = context.fetchResource(StructureDefinition.class, url); + source = context.fetchResource(StructureDefinition.class, url, source); if (source == null) { return null; } @@ -4148,7 +4148,7 @@ public class ProfileUtilities extends TranslatingUtilities { profiles.add(profile); keyRows.clear(); - genElement(defFile == null ? null : defFile+"#", gen, model.getRows(), list.get(0), list, profiles, diff, profileBaseFileName, null, snapshot, corePath, imagePath, true, logicalModel, profile.getDerivation() == TypeDerivationRule.CONSTRAINT && usesMustSupport(list), allInvariants, null, mustSupport, rc, anchorPrefix); + genElement(defFile == null ? null : defFile+"#", gen, model.getRows(), list.get(0), list, profiles, diff, profileBaseFileName, null, snapshot, corePath, imagePath, true, logicalModel, profile.getDerivation() == TypeDerivationRule.CONSTRAINT && usesMustSupport(list), allInvariants, null, mustSupport, rc, anchorPrefix, profile); try { return gen.generate(model, imagePath, 0, outputTracker); } catch (org.hl7.fhir.exceptions.FHIRException e) { @@ -4244,7 +4244,7 @@ public class ProfileUtilities extends TranslatingUtilities { private Row genElement(String defPath, HierarchicalTableGenerator gen, List rows, ElementDefinition element, List all, List profiles, boolean showMissing, String profileBaseFileName, Boolean extensions, - boolean snapshot, String corePath, String imagePath, boolean root, boolean logicalModel, boolean isConstraintMode, boolean allInvariants, Row slicingRow, boolean mustSupport, RenderingContext rc, String anchorPrefix) throws IOException, FHIRException { + boolean snapshot, String corePath, String imagePath, boolean root, boolean logicalModel, boolean isConstraintMode, boolean allInvariants, Row slicingRow, boolean mustSupport, RenderingContext rc, String anchorPrefix, Resource srcSD) throws IOException, FHIRException { Row originalRow = slicingRow; StructureDefinition profile = profiles == null ? null : profiles.get(profiles.size()-1); Row typesRow = null; @@ -4393,7 +4393,7 @@ public class ProfileUtilities extends TranslatingUtilities { Row childRow = chooseChildRowByGroup(gen, currRow, groups, child, element, isConstraintMode); if (logicalModel || !child.getPath().endsWith(".id") || (child.getPath().endsWith(".id") && (profile != null) && (profile.getDerivation() == TypeDerivationRule.CONSTRAINT))) { - currRow = genElement(defPath, gen, childRow.getSubRows(), child, all, profiles, showMissing, profileBaseFileName, isExtension, snapshot, corePath, imagePath, false, logicalModel, isConstraintMode, allInvariants, currRow, mustSupport, rc, anchorPrefix); + currRow = genElement(defPath, gen, childRow.getSubRows(), child, all, profiles, showMissing, profileBaseFileName, isExtension, snapshot, corePath, imagePath, false, logicalModel, isConstraintMode, allInvariants, currRow, mustSupport, rc, anchorPrefix, srcSD); } } } @@ -4403,7 +4403,7 @@ public class ProfileUtilities extends TranslatingUtilities { // genElement(defPath, gen, row.getSubRows(), child, all, profiles, showMissing, profileBaseFileName, true, false, corePath, imagePath, false, logicalModel, isConstraintMode, allInvariants); } if (typesRow != null && !element.prohibited()) { - makeChoiceRows(typesRow.getSubRows(), element, gen, corePath, profileBaseFileName, mustSupport); + makeChoiceRows(typesRow.getSubRows(), element, gen, corePath, profileBaseFileName, mustSupport, srcSD); } } return slicingRow; @@ -4600,7 +4600,7 @@ public class ProfileUtilities extends TranslatingUtilities { return key != null && key.startsWith("ele-") || key.startsWith("res-") || key.startsWith("ext-") || key.startsWith("dom-") || key.startsWith("dr-"); } - private void makeChoiceRows(List subRows, ElementDefinition element, HierarchicalTableGenerator gen, String corePath, String profileBaseFileName, boolean mustSupportMode) { + private void makeChoiceRows(List subRows, ElementDefinition element, HierarchicalTableGenerator gen, String corePath, String profileBaseFileName, boolean mustSupportMode, Resource src) { // create a child for each choice for (TypeRefComponent tr : element.getType()) { if (!mustSupportMode || allTypesMustSupport(element) || isMustSupport(tr)) { @@ -4629,7 +4629,7 @@ public class ProfileUtilities extends TranslatingUtilities { if (!mustSupportMode || allProfilesMustSupport(tr.getTargetProfile()) || isMustSupport(rt)) { if (!first) c.getPieces().add(gen.new Piece(null, " | ", null)); - genTargetLink(gen, profileBaseFileName, corePath, c, tr, rt.getValue()); + genTargetLink(gen, profileBaseFileName, corePath, c, tr, rt.getValue(), src); if (!mustSupportMode && isMustSupport(rt) && element.getMustSupport()) { c.addPiece(gen.new Piece(null, " ", null)); c.addStyledText(translate("sd.table", "This target must be supported"), "S", "white", "red", null, false); @@ -4680,7 +4680,7 @@ public class ProfileUtilities extends TranslatingUtilities { for (CanonicalType pt : tr.getProfile()) { if (!mustSupportMode || allProfilesMustSupport(tr.getProfile()) || isMustSupport(pt)) { if (first) first = false; else typeCell.addPiece(gen.new Piece(null, " | ", null)); - StructureDefinition psd = context.fetchResource(StructureDefinition.class, pt.getValue()); + StructureDefinition psd = context.fetchResource(StructureDefinition.class, pt.getValue(), src); if (psd == null) typeCell.addPiece(gen.new Piece(null, "?gen-e2?", null)); else @@ -4901,7 +4901,7 @@ public class ProfileUtilities extends TranslatingUtilities { if (!c.getPieces().isEmpty()) c.addPiece(gen.new Piece("br")); String fullUrl = url.startsWith("#") ? baseURL+url : url; - StructureDefinition ed = context.fetchResource(StructureDefinition.class, url); + StructureDefinition ed = context.fetchResource(StructureDefinition.class, url, profile); String ref = null; String ref2 = null; String fixedUrl = null; @@ -5417,7 +5417,7 @@ public class ProfileUtilities extends TranslatingUtilities { if (!c.getPieces().isEmpty()) c.addPiece(gen.new Piece("br")); String fullUrl = url.startsWith("#") ? baseURL+url : url; - StructureDefinition ed = context.fetchResource(StructureDefinition.class, url); + StructureDefinition ed = context.fetchResource(StructureDefinition.class, url, profile); String ref = null; if (ed != null) { String p = ed.getUserString("path"); @@ -5661,7 +5661,7 @@ public class ProfileUtilities extends TranslatingUtilities { code = url.substring(1); } else if (context != null) { String[] parts = url.split("\\#"); - profile = context.fetchResource(StructureDefinition.class, parts[0]); + profile = context.fetchResource(StructureDefinition.class, parts[0], source); code = parts.length == 1 ? null : parts[1]; } if (profile == null) @@ -6075,7 +6075,7 @@ public class ProfileUtilities extends TranslatingUtilities { if (!structure.hasSnapshot()) throw new DefinitionException(context.formatMessage(I18nConstants.NEEDS_A_SNAPSHOT)); - StructureDefinition base = context.fetchResource(StructureDefinition.class, structure.getBaseDefinition()); + StructureDefinition base = context.fetchResource(StructureDefinition.class, structure.getBaseDefinition(), structure); if (base != null) { SchematronWriter sch = new SchematronWriter(dest, SchematronType.PROFILE, base.getName()); @@ -6479,7 +6479,7 @@ public class ProfileUtilities extends TranslatingUtilities { sd.getSnapshot().getElement().add(sd.getDifferential().getElementFirstRep().copy()); if (sd.hasBaseDefinition()) { - StructureDefinition base = context.fetchResource(StructureDefinition.class, sd.getBaseDefinition()); + StructureDefinition base = context.fetchResource(StructureDefinition.class, sd.getBaseDefinition(), sd); if (base == null) throw new FHIRException(context.formatMessage(I18nConstants.UNABLE_TO_FIND_BASE_DEFINITION_FOR_LOGICAL_MODEL__FROM_, sd.getBaseDefinition(), sd.getUrl())); copyElements(sd, base.getSnapshot().getElement()); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/R5ExtensionsLoader.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/R5ExtensionsLoader.java index 5ce8b9ffd..c73b13472 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/R5ExtensionsLoader.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/R5ExtensionsLoader.java @@ -13,7 +13,6 @@ import org.hl7.fhir.exceptions.FHIRFormatError; import org.hl7.fhir.r5.conformance.R5ExtensionsLoader.Loadable; import org.hl7.fhir.r5.context.ContextUtilities; import org.hl7.fhir.r5.context.IWorkerContext; -import org.hl7.fhir.r5.context.IWorkerContext.PackageVersion; import org.hl7.fhir.r5.formats.JsonParser; import org.hl7.fhir.r5.model.CanonicalResource; import org.hl7.fhir.r5.model.CanonicalType; @@ -22,6 +21,7 @@ import org.hl7.fhir.r5.model.ElementDefinition; import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.r5.model.ValueSet; import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent; +import org.hl7.fhir.r5.model.PackageInformation; import org.hl7.fhir.r5.model.StructureDefinition.TypeDerivationRule; import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent; import org.hl7.fhir.r5.utils.ResourceSorters; @@ -64,7 +64,7 @@ public class R5ExtensionsLoader { private Map> codeSystems; private List> structures; private IWorkerContext context; - private PackageVersion pd; + private PackageInformation pd; private JsonParser json; public R5ExtensionsLoader(BasePackageCacheManager pcm, IWorkerContext context) { @@ -79,7 +79,7 @@ public class R5ExtensionsLoader { public void load() throws FHIRException, IOException { pck = pcm.loadPackage("hl7.fhir.r5.core", "current"); - pd = new PackageVersion(pck.name(), pck.version(), pck.dateAsDate()); + pd = new PackageInformation(pck); String[] types = new String[] { "StructureDefinition", "ValueSet", "CodeSystem" }; json = new JsonParser(); @@ -140,7 +140,7 @@ public class R5ExtensionsLoader { } } - private void loadValueSet(String url, IWorkerContext context, Map> valueSets, Map> codeSystems, PackageVersion pd) throws FHIRFormatError, FileNotFoundException, IOException { + private void loadValueSet(String url, IWorkerContext context, Map> valueSets, Map> codeSystems, PackageInformation pd) throws FHIRFormatError, FileNotFoundException, IOException { if (valueSets.containsKey(url)) { ValueSet vs = valueSets.get(url).getResource(); context.cacheResourceFromPackage(vs, pd); 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 9c2b11758..b68aaad0e 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 @@ -84,6 +84,7 @@ import org.hl7.fhir.r5.model.NamingSystem.NamingSystemIdentifierType; import org.hl7.fhir.r5.model.NamingSystem.NamingSystemUniqueIdComponent; import org.hl7.fhir.r5.model.OperationDefinition; import org.hl7.fhir.r5.model.OperationOutcome; +import org.hl7.fhir.r5.model.PackageInformation; import org.hl7.fhir.r5.model.Parameters; import org.hl7.fhir.r5.model.Parameters.ParametersParameterComponent; import org.hl7.fhir.r5.model.PlanDefinition; @@ -115,6 +116,7 @@ import org.hl7.fhir.r5.terminologies.ValueSetExpander.TerminologyServiceErrorCla import org.hl7.fhir.r5.terminologies.ValueSetExpander.ValueSetExpansionOutcome; import org.hl7.fhir.r5.terminologies.ValueSetExpanderSimple; 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.validation.ValidationContextCarrier; import org.hl7.fhir.utilities.OIDUtils; @@ -137,6 +139,8 @@ import javax.annotation.Nonnull; public abstract class BaseWorkerContext extends I18nBase implements IWorkerContext{ + private static final boolean QA_CHECK_REFERENCE_SOURCE = true; + public class ResourceProxy { private Resource resource; private CanonicalResourceProxy proxy; @@ -250,6 +254,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte protected ILoggingService logger = new SystemOutLoggingService(); protected Parameters expParameters; private TranslationServices translator = new NullTranslator(); + private Map packages = new HashMap<>(); @Getter protected TerminologyCache txCache; @@ -336,10 +341,13 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte } - public void registerResourceFromPackage(CanonicalResourceProxy r, PackageVersion packageInfo) throws FHIRException { + public void registerResourceFromPackage(CanonicalResourceProxy r, PackageInformation packageInfo) throws FHIRException { PackageHackerR5.fixLoadedResource(r, packageInfo); synchronized (lock) { + if (packageInfo != null) { + packages.put(packageInfo.getVID(), packageInfo); + } if (r.getId() != null) { Map map = allResourcesById.get(r.getType()); if (map == null) { @@ -418,9 +426,13 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte } } - public void cacheResourceFromPackage(Resource r, PackageVersion packageInfo) throws FHIRException { + public void cacheResourceFromPackage(Resource r, PackageInformation packageInfo) throws FHIRException { synchronized (lock) { + if (packageInfo != null) { + packages.put(packageInfo.getVID(), packageInfo); + } + if (r.getId() != null) { Map map = allResourcesById.get(r.fhirType()); if (map == null) { @@ -713,9 +725,9 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte } @Override - public ValueSetExpansionOutcome expandVS(ElementDefinitionBindingComponent binding, boolean cacheOk, boolean heirarchical) throws FHIRException { + public ValueSetExpansionOutcome expandVS(Resource src, ElementDefinitionBindingComponent binding, boolean cacheOk, boolean heirarchical) throws FHIRException { ValueSet vs = null; - vs = fetchResource(ValueSet.class, binding.getValueSet()); + vs = fetchResource(ValueSet.class, binding.getValueSet(), src); if (vs == null) { throw new FHIRException(formatMessage(I18nConstants.UNABLE_TO_RESOLVE_VALUE_SET_, binding.getValueSet())); } @@ -1239,18 +1251,18 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte private boolean addDependentResources(Parameters pin, ValueSet vs) { boolean cache = false; for (ConceptSetComponent inc : vs.getCompose().getInclude()) { - cache = addDependentResources(pin, inc) || cache; + cache = addDependentResources(pin, inc, vs) || cache; } for (ConceptSetComponent inc : vs.getCompose().getExclude()) { - cache = addDependentResources(pin, inc) || cache; + cache = addDependentResources(pin, inc, vs) || cache; } return cache; } - private boolean addDependentResources(Parameters pin, ConceptSetComponent inc) { + private boolean addDependentResources(Parameters pin, ConceptSetComponent inc, Resource src) { boolean cache = false; for (CanonicalType c : inc.getValueSet()) { - ValueSet vs = fetchResource(ValueSet.class, c.getValue()); + ValueSet vs = fetchResource(ValueSet.class, c.getValue(), src); if (vs != null) { pin.addParameter().setName("tx-resource").setResource(vs); if (isTxCaching && cacheId == null || !cached.contains(vs.getVUrl())) { @@ -1260,7 +1272,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte addDependentResources(pin, vs); } } - CodeSystem cs = fetchResource(CodeSystem.class, inc.getSystem()); + CodeSystem cs = fetchResource(CodeSystem.class, inc.getSystem(), src); if (cs != null && (cs.getContent() == CodeSystemContentMode.COMPLETE || cs.getContent() == CodeSystemContentMode.FRAGMENT)) { pin.addParameter().setName("tx-resource").setResource(cs); if (isTxCaching && cacheId == null || !cached.contains(cs.getVUrl())) { @@ -1397,16 +1409,33 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte return fetchResourceWithExceptionByVersion(cls, uri, null, null); } - public T fetchResourceWithException(Class class_, String uri, CanonicalResource source) throws FHIRException { - return fetchResourceWithExceptionByVersion(class_, uri, null, source); + public T fetchResourceWithException(Class class_, String uri, Resource sourceForReference) throws FHIRException { + return fetchResourceWithExceptionByVersion(class_, uri, null, sourceForReference); } @SuppressWarnings("unchecked") - public T fetchResourceWithExceptionByVersion(Class class_, String uri, String version, CanonicalResource source) throws FHIRException { + public T fetchResourceWithExceptionByVersion(Class class_, String uri, String version, Resource sourceForReference) throws FHIRException { if (uri == null) { return null; } + + if (QA_CHECK_REFERENCE_SOURCE) { + // it can be tricky to trace the source of a reference correctly. The code isn't water tight, + // particularly around snapshot generation. Enable this code to check that the references are + // correct (but it's slow) + if (sourceForReference != null && uri.contains("ValueSet")) { + if (!ResourceUtilities.hasURL(uri, sourceForReference)) { + System.out.print("Claimed source doesn't have url in it: "+sourceForReference.fhirType()+"/"+sourceForReference.getIdPart()+" -> "+uri); + System.out.println(); + } + } + } + List pvlist = new ArrayList<>(); + if (sourceForReference != null && sourceForReference.getSourcePackage() != null) { + populatePVList(pvlist, sourceForReference.getSourcePackage()); + } + if (class_ == StructureDefinition.class) { uri = ProfileUtilities.sdNs(uri, null); } @@ -1425,49 +1454,49 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte } if (class_ == Resource.class || class_ == null) { if (structures.has(uri)) { - return (T) structures.get(uri, version); + return (T) structures.get(uri, version, pvlist); } if (guides.has(uri)) { - return (T) guides.get(uri, version); + return (T) guides.get(uri, version, pvlist); } if (capstmts.has(uri)) { - return (T) capstmts.get(uri, version); + return (T) capstmts.get(uri, version, pvlist); } if (measures.has(uri)) { - return (T) measures.get(uri, version); + return (T) measures.get(uri, version, pvlist); } if (libraries.has(uri)) { - return (T) libraries.get(uri, version); + return (T) libraries.get(uri, version, pvlist); } if (valueSets.has(uri)) { - return (T) valueSets.get(uri, version); + return (T) valueSets.get(uri, version, pvlist); } if (codeSystems.has(uri)) { - return (T) codeSystems.get(uri, version); + return (T) codeSystems.get(uri, version, pvlist); } if (operations.has(uri)) { - return (T) operations.get(uri, version); + return (T) operations.get(uri, version, pvlist); } if (searchParameters.has(uri)) { - return (T) searchParameters.get(uri, version); + return (T) searchParameters.get(uri, version, pvlist); } if (plans.has(uri)) { - return (T) plans.get(uri, version); + return (T) plans.get(uri, version, pvlist); } if (maps.has(uri)) { - return (T) maps.get(uri, version); + return (T) maps.get(uri, version, pvlist); } if (transforms.has(uri)) { - return (T) transforms.get(uri, version); + return (T) transforms.get(uri, version, pvlist); } if (actors.has(uri)) { - return (T) transforms.get(uri, version); + return (T) transforms.get(uri, version, pvlist); } if (requirements.has(uri)) { - return (T) transforms.get(uri, version); + return (T) transforms.get(uri, version, pvlist); } if (questionnaires.has(uri)) { - return (T) questionnaires.get(uri, version); + return (T) questionnaires.get(uri, version, pvlist); } for (Map rt : allResourcesById.values()) { @@ -1492,47 +1521,47 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte // } return null; } else if (class_ == ImplementationGuide.class) { - return (T) guides.get(uri, version); + return (T) guides.get(uri, version, pvlist); } else if (class_ == CapabilityStatement.class) { - return (T) capstmts.get(uri, version); + return (T) capstmts.get(uri, version, pvlist); } else if (class_ == Measure.class) { - return (T) measures.get(uri, version); + return (T) measures.get(uri, version, pvlist); } else if (class_ == Library.class) { - return (T) libraries.get(uri, version); + return (T) libraries.get(uri, version, pvlist); } else if (class_ == StructureDefinition.class) { - return (T) structures.get(uri, version); + return (T) structures.get(uri, version, pvlist); } else if (class_ == StructureMap.class) { - return (T) transforms.get(uri, version); + return (T) transforms.get(uri, version, pvlist); } else if (class_ == ValueSet.class) { - return (T) valueSets.get(uri, version); + return (T) valueSets.get(uri, version, pvlist); } else if (class_ == CodeSystem.class) { - return (T) codeSystems.get(uri, version); + return (T) codeSystems.get(uri, version, pvlist); } else if (class_ == ConceptMap.class) { - return (T) maps.get(uri, version); + return (T) maps.get(uri, version, pvlist); } else if (class_ == ActorDefinition.class) { - return (T) actors.get(uri, version); + return (T) actors.get(uri, version, pvlist); } else if (class_ == Requirements.class) { - return (T) requirements.get(uri, version); + return (T) requirements.get(uri, version, pvlist); } else if (class_ == PlanDefinition.class) { - return (T) plans.get(uri, version); + return (T) plans.get(uri, version, pvlist); } else if (class_ == OperationDefinition.class) { OperationDefinition od = operations.get(uri, version); return (T) od; } else if (class_ == Questionnaire.class) { - return (T) questionnaires.get(uri, version); + return (T) questionnaires.get(uri, version, pvlist); } else if (class_ == SearchParameter.class) { - SearchParameter res = searchParameters.get(uri, version); + SearchParameter res = searchParameters.get(uri, version, pvlist); return (T) res; } if (class_ == CodeSystem.class && codeSystems.has(uri)) { - return (T) codeSystems.get(uri, version); + return (T) codeSystems.get(uri, version, pvlist); } if (class_ == ValueSet.class && valueSets.has(uri)) { - return (T) valueSets.get(uri, version); + return (T) valueSets.get(uri, version, pvlist); } if (class_ == Questionnaire.class) { - return (T) questionnaires.get(uri, version); + return (T) questionnaires.get(uri, version, pvlist); } if (supportedCodeSystems.contains(uri)) { return null; @@ -1541,7 +1570,26 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte } } - public PackageVersion getPackageForUrl(String uri) { + private void populatePVList(List pvlist, PackageInformation sourcePackage) { + pvlist.add(sourcePackage.getVID()); + List toadd = new ArrayList<>(); + do { + toadd.clear(); + for (String s : pvlist) { + PackageInformation pi = packages.get(s); + if (pi != null) { + for (String v : pi.getDependencies()) { + if (!pvlist.contains(v) && !toadd.contains(v)) { + toadd.add(v); + } + } + } + } + pvlist.addAll(toadd); + } while (toadd.size() > 0); + } + + public PackageInformation getPackageForUrl(String uri) { if (uri == null) { return null; } @@ -1835,9 +1883,9 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte } } - public T fetchResource(Class class_, String uri, CanonicalResource source) { + public T fetchResource(Class class_, String uri, Resource sourceForReference) { try { - return fetchResourceWithException(class_, uri, source); + return fetchResourceWithException(class_, uri, sourceForReference); } catch (FHIRException e) { throw new Error(e); } @@ -2345,7 +2393,4 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte return this; } - public void registerVSACRule(boolean byVersion) { - valueSets.registerSpecialRule(valueSets.new VSACRule(byVersion)); - } } \ No newline at end of file diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/CanonicalResourceManager.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/CanonicalResourceManager.java index 633f2c9f5..62b35613d 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/CanonicalResourceManager.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/CanonicalResourceManager.java @@ -3,9 +3,9 @@ package org.hl7.fhir.r5.context; import java.util.*; import org.hl7.fhir.exceptions.FHIRException; -import org.hl7.fhir.r5.context.IWorkerContext.PackageVersion; import org.hl7.fhir.r5.model.CanonicalResource; import org.hl7.fhir.r5.model.CodeSystem; +import org.hl7.fhir.r5.model.PackageInformation; import org.hl7.fhir.r5.terminologies.CodeSystemUtilities; import org.hl7.fhir.utilities.VersionUtilities; @@ -110,15 +110,15 @@ public class CanonicalResourceManager { private class CachedCanonicalResource { private T1 resource; private CanonicalResourceProxy proxy; - private PackageVersion packageInfo; + private PackageInformation packageInfo; - public CachedCanonicalResource(T1 resource, PackageVersion packageInfo) { + public CachedCanonicalResource(T1 resource, PackageInformation packageInfo) { super(); this.resource = resource; this.packageInfo = packageInfo; } - public CachedCanonicalResource(CanonicalResourceProxy proxy, PackageVersion packageInfo) { + public CachedCanonicalResource(CanonicalResourceProxy proxy, PackageInformation packageInfo) { super(); this.proxy = proxy; this.packageInfo = packageInfo; @@ -134,13 +134,13 @@ public class CanonicalResourceManager { synchronized (this) { resource = res; } - resource.setUserData("package", packageInfo); + resource.setSourcePackage(packageInfo); proxy = null; } return resource; } - public PackageVersion getPackageInfo() { + public PackageInformation getPackageInfo() { return packageInfo; } public String getUrl() { @@ -158,7 +158,7 @@ public class CanonicalResourceManager { @Override public String toString() { - return resource != null ? resource.fhirType()+"/"+resource.getId()+": "+resource.getUrl()+"|"+resource.getVersion() : proxy.toString(); + return resource != null ? resource.fhirType()+"/"+resource.getId()+"["+resource.getUrl()+"|"+resource.getVersion()+"]" : proxy.toString(); } } @@ -188,6 +188,8 @@ public class CanonicalResourceManager { private boolean enforceUniqueId; private List> list = new ArrayList<>(); + private Map>> listForId = new HashMap<>(); + private Map>> listForUrl = new HashMap<>(); private Map> map = new HashMap<>(); private String version; // for debugging purposes @@ -215,7 +217,7 @@ public class CanonicalResourceManager { map.putAll(source.map); } - public void register(CanonicalResourceProxy r, PackageVersion packgeInfo) { + public void register(CanonicalResourceProxy r, PackageInformation packgeInfo) { if (!r.hasId()) { throw new FHIRException("An id is required for a deferred load resource"); } @@ -223,7 +225,7 @@ public class CanonicalResourceManager { see(cr); } - public void see(T r, PackageVersion packgeInfo) { + public void see(T r, PackageInformation packgeInfo) { if (r != null) { if (!r.hasId()) { r.setId(UUID.randomUUID().toString()); @@ -234,21 +236,27 @@ public class CanonicalResourceManager { } public void see(CachedCanonicalResource cr) { + // -- 1. exit conditions ----------------------------------------------------------------------------- + // ignore UTG NUCC erroneous code system if (cr.getPackageInfo() != null && cr.getPackageInfo().getId() != null && cr.getPackageInfo().getId().startsWith("hl7.terminology") - && Arrays.stream(INVALID_TERMINOLOGY_URLS).anyMatch((it)->it.equals(cr.getUrl())) - ) { + && Arrays.stream(INVALID_TERMINOLOGY_URLS).anyMatch((it)->it.equals(cr.getUrl()))) { + return; + } + if (map.get(cr.getUrl()) != null && (cr.getPackageInfo() != null && cr.getPackageInfo().isExamplesPackage())) { return; - } - - if (enforceUniqueId && map.containsKey(cr.getId())) { - drop(cr.getId()); } + // -- 2. preparation ----------------------------------------------------------------------------- if (cr.resource != null) { - cr.resource.setUserData("package", cr.getPackageInfo()); + cr.resource.setSourcePackage(cr.getPackageInfo()); + } + + // -- 3. deleting existing content --------------------------------------------------------------- + if (enforceUniqueId && map.containsKey(cr.getId())) { + drop(cr.getId()); } // special case logic for UTG support prior to version 5 @@ -260,33 +268,104 @@ public class CanonicalResourceManager { } } for (CachedCanonicalResource n : toDrop) { - drop(n.getId()); + drop(n); } } - CachedCanonicalResource existing = cr.hasVersion() ? map.get(cr.getUrl()+"|"+cr.getVersion()) : map.get(cr.getUrl()+"|#0"); - if (map.get(cr.getUrl()) != null && (cr.getPackageInfo() != null && cr.getPackageInfo().isExamplesPackage())) { - return; - } - if (existing != null) { - list.remove(existing); - } +// CachedCanonicalResource existing = cr.hasVersion() ? map.get(cr.getUrl()+"|"+cr.getVersion()) : map.get(cr.getUrl()+"|#0"); +// if (existing != null) { +// drop(existing); // was list.remove(existing) +// } + // -- 4. ok we add it to the list --------------------------------------------------------------- + if (!enforceUniqueId) { + if (!listForId.containsKey(cr.getId())) { + listForId.put(cr.getId(), new ArrayList<>()); + } + List> set = listForId.get(cr.getId()); + set.add(cr); + } list.add(cr); - map.put(cr.getId(), cr); // we do this so we can drop by id - map.put(cr.getUrl(), cr); + if (!listForUrl.containsKey(cr.getUrl())) { + listForUrl.put(cr.getUrl(), new ArrayList<>()); + } + List> set = listForUrl.get(cr.getUrl()); + set.add(cr); + Collections.sort(set, new MetadataResourceVersionComparator>()); - if (cr.getUrl() != null) { - // first, this is the correct reosurce for this version (if it has a version) - if (cr.hasVersion()) { - map.put(cr.getUrl()+"|"+cr.getVersion(), cr); - } else { - map.put(cr.getUrl()+"|#0", cr); + // -- 4. add to the map all the ways --------------------------------------------------------------- + String pv = cr.getPackageInfo() != null ? cr.getPackageInfo().getVID() : null; + map.put(cr.getId(), cr); // we do this so we can drop by id - if not enforcing id, it's just the most recent resource with this id + map.put(cr.hasVersion() ? cr.getUrl()+"|"+cr.getVersion() : cr.getUrl()+"|#0", cr); + if (pv != null) { + map.put(pv+":"+(cr.hasVersion() ? cr.getUrl()+"|"+cr.getVersion() : cr.getUrl()+"|#0"), cr); + } + int ndx = set.indexOf(cr); + if (ndx == set.size()-1) { + map.put(cr.getUrl(), cr); + if (pv != null) { + map.put(pv+":"+cr.getUrl(), cr); + } + } + String mm = VersionUtilities.getMajMin(cr.getVersion()); + if (mm != null) { + if (pv != null) { + map.put(pv+":"+cr.getUrl()+"|"+mm, cr); + } + if (set.size() - 1 == ndx) { + map.put(cr.getUrl()+"|"+mm, cr); + } else { + for (int i = set.size() - 1; i > ndx; i--) { + if (mm.equals(VersionUtilities.getMajMin(set.get(i).getVersion()))) { + return; + } + map.put(cr.getUrl()+"|"+mm, cr); + } } - updateList(cr.getUrl(), cr.getVersion()); } } - private boolean isBasePackage(PackageVersion packageInfo) { + public void drop(CachedCanonicalResource cr) { + while (map.values().remove(cr)); + list.remove(cr); + List> set = listForUrl.get(cr.getUrl()); + if (set != null) { // it really should be + boolean last = set.indexOf(cr) == set.size()-1; + set.remove(cr); + if (!set.isEmpty()) { + CachedCanonicalResource crl = set.get(set.size()-1); + if (last) { + map.put(crl.getUrl(), crl); + } + String mm = VersionUtilities.getMajMin(cr.getVersion()); + if (mm != null) { + for (int i = set.size()-1; i >= 0; i--) { + if (mm.equals(VersionUtilities.getMajMin(set.get(i).getVersion()))) { + map.put(cr.getUrl()+"|"+mm, set.get(i)); + break; + } + } + } + } + } + } + + public void drop(String id) { + if (enforceUniqueId) { + CachedCanonicalResource cr = map.get(id); + if (cr != null) { + drop(cr); + } + } else { + List> set = listForId.get(id); + if (set != null) { // it really should be + for (CachedCanonicalResource i : set) { + drop(i); + } + } + } + } + + private boolean isBasePackage(PackageInformation packageInfo) { return packageInfo == null ? false : VersionUtilities.isCorePackage(packageInfo.getId()); } @@ -299,7 +378,6 @@ public class CanonicalResourceManager { } if (rl.size() > 0) { // sort by version as much as we are able - Collections.sort(rl, new MetadataResourceVersionComparator>()); // the current is the latest map.put(url, rl.get(rl.size()-1)); // now, also, the latest for major/minor @@ -320,27 +398,23 @@ public class CanonicalResourceManager { } - public T get(String url) { - return map.containsKey(url) ? map.get(url).getResource() : null; - } - - public PackageVersion getPackageInfo(String system, String version) { - if (version == null) { - return map.containsKey(system) ? map.get(system).getPackageInfo() : null; - } else { - if (map.containsKey(system+"|"+version)) - return map.get(system+"|"+version).getPackageInfo(); - String mm = VersionUtilities.getMajMin(version); - if (mm != null && map.containsKey(system+"|"+mm)) - return map.get(system+"|"+mm).getPackageInfo(); - else - return null; - } - } - public boolean has(String url) { return map.containsKey(url); } + + public boolean has(String system, String version) { + if (map.containsKey(system+"|"+version)) + return true; + String mm = VersionUtilities.getMajMin(version); + if (mm != null) + return map.containsKey(system+"|"+mm); + else + return false; + } + + public T get(String url) { + return map.containsKey(url) ? map.get(url).getResource() : null; + } public T get(String system, String version) { if (version == null) { @@ -356,45 +430,75 @@ public class CanonicalResourceManager { } } - public boolean has(String system, String version) { - if (map.containsKey(system+"|"+version)) - return true; - String mm = VersionUtilities.getMajMin(version); - if (mm != null) - return map.containsKey(system+"|"+mm); - else - return false; + + /** + * This is asking for a packaged version aware resolution + * + * if we can resolve the reference in the package dependencies, we will. if we can't + * then we fall back to the non-package approach + * + * The context has to prepare the pvlist based on the original package + * @param url + * @param srcInfo + * @return + */ + public T get(String url, List pvlist) { + for (String pv : pvlist) { + if (map.containsKey(pv+":"+url)) { + return map.get(pv+":"+url).getResource(); + } + } + return map.containsKey(url) ? map.get(url).getResource() : null; } + public T get(String system, String version, List pvlist) { + if (version == null) { + return get(system, pvlist); + } else { + for (String pv : pvlist) { + if (map.containsKey(pv+":"+system+"|"+version)) + return map.get(pv+":"+system+"|"+version).getResource(); + } + String mm = VersionUtilities.getMajMin(version); + if (mm != null && map.containsKey(system+"|"+mm)) + for (String pv : pvlist) { + if (map.containsKey(pv+":"+system+"|"+mm)) + return map.get(pv+":"+system+"|"+mm).getResource(); + } + + if (map.containsKey(system+"|"+version)) + return map.get(system+"|"+version).getResource(); + if (mm != null && map.containsKey(system+"|"+mm)) + return map.get(system+"|"+mm).getResource(); + else + return null; + } + } + + + + public PackageInformation getPackageInfo(String system, String version) { + if (version == null) { + return map.containsKey(system) ? map.get(system).getPackageInfo() : null; + } else { + if (map.containsKey(system+"|"+version)) + return map.get(system+"|"+version).getPackageInfo(); + String mm = VersionUtilities.getMajMin(version); + if (mm != null && map.containsKey(system+"|"+mm)) + return map.get(system+"|"+mm).getPackageInfo(); + else + return null; + } + } + + + + public int size() { return list.size(); } - public void drop(String id) { - CachedCanonicalResource res = null; - do { - res = null; - for (CachedCanonicalResource t : list) { - if (t.getId().equals(id)) { - res = t; - } - } - if (res != null) { - list.remove(res); - map.remove(id); - map.remove(res.getUrl()); - if (res.hasVersion()) { - map.remove(res.getUrl()+"|"+res.getVersion()); - String mm = VersionUtilities.getMajMin(res.getVersion()); - if (mm != null) { - map.remove(res.getUrl()+"|"+mm); - } - } - updateList(res.getUrl(), res.getVersion()); - } - } while (res != null); - } - + public void listAll(List result) { for (CachedCanonicalResource t : list) { @@ -437,5 +541,6 @@ public class CanonicalResourceManager { public boolean isEnforceUniqueId() { return enforceUniqueId; } - + + } \ No newline at end of file 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 158b42a3c..b1b7815b2 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 @@ -239,7 +239,7 @@ public class ContextUtilities implements ProfileKnowledgeProvider { if ((!p.hasSnapshot() || isProfileNeedsRegenerate(p) ) && (ifLogical || p.getKind() != StructureDefinitionKind.LOGICAL)) { if (!p.hasBaseDefinition()) throw new DefinitionException(context.formatMessage(I18nConstants.PROFILE___HAS_NO_BASE_AND_NO_SNAPSHOT, p.getName(), p.getUrl())); - StructureDefinition sd = context.fetchResource(StructureDefinition.class, p.getBaseDefinition()); + StructureDefinition sd = context.fetchResource(StructureDefinition.class, p.getBaseDefinition(), p); if (sd == null && "http://hl7.org/fhir/StructureDefinition/Base".equals(p.getBaseDefinition())) { sd = ProfileUtilities.makeBaseDefinition(p.getFhirVersion()); } 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 f41bd5da6..0b34be2ac 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 @@ -8,19 +8,19 @@ import java.util.Date; /* Copyright (c) 2011+, HL7, Inc. All rights reserved. - + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * Neither the name of HL7 nor the names of its contributors may be used to + * Neither the name of HL7 nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. @@ -31,7 +31,7 @@ import java.util.Date; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - + */ @@ -58,6 +58,7 @@ import org.hl7.fhir.r5.model.Coding; import org.hl7.fhir.r5.model.ConceptMap; import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingComponent; import org.hl7.fhir.r5.model.NamingSystem; +import org.hl7.fhir.r5.model.PackageInformation; import org.hl7.fhir.r5.model.Parameters; import org.hl7.fhir.r5.model.Resource; import org.hl7.fhir.r5.model.StructureDefinition; @@ -102,7 +103,7 @@ import javax.annotation.Nonnull; */ public interface IWorkerContext { - + class ValidationResult { private ConceptDefinitionComponent definition; private String system; @@ -110,7 +111,7 @@ public interface IWorkerContext { private String message; private TerminologyServiceErrorClass errorClass; private String txLink; - + @Override public String toString() { return "ValidationResult [definition=" + definition + ", system=" + system + ", severity=" + severity + ", message=" + message + ", errorClass=" @@ -121,7 +122,7 @@ public interface IWorkerContext { this.severity = severity; this.message = message; } - + public ValidationResult(String system, ConceptDefinitionComponent definition) { this.system = system; this.definition = definition; @@ -133,7 +134,7 @@ public interface IWorkerContext { this.system = system; this.definition = definition; } - + public ValidationResult(IssueSeverity severity, String message, TerminologyServiceErrorClass errorClass) { this.severity = severity; this.message = message; @@ -207,7 +208,7 @@ public interface IWorkerContext { public boolean hasMessage() { return message != null; } - + public Coding asCoding() { if (isOk() && definition != null && definition.getCode() != null) { return new Coding(system, definition.getCode(), definition.getDisplay()); @@ -221,7 +222,7 @@ public interface IWorkerContext { private Coding coding; private ValidationResult result; private CacheToken cacheToken; - + public CodingValidationRequest(Coding coding) { super(); this.coding = coding; @@ -260,86 +261,17 @@ public interface IWorkerContext { public void setCacheToken(CacheToken cacheToken) { this.cacheToken = cacheToken; } - - + + } - public class PackageVersion { - private String id; - private String version; - private Date date; - - public PackageVersion(String source, Date date) { - if (source == null) { - throw new Error("Source cannot be null"); - } - if (!source.contains("#")) { - throw new FHIRException("Source "); - } - id = source.substring(0, source.indexOf("#")); - version = source.substring(source.indexOf("#")+1); - this.date = date; - } - public PackageVersion(String id, String version, Date date) { - super(); - this.id = id; - this.version = version; - this.date = date; - } - - public String getId() { - return id; - } - public String getVersion() { - return version; - } - public boolean isExamplesPackage() { - boolean b = id.startsWith("hl7.fhir.") && id.endsWith(".examples"); - return b; - } - @Override - public String toString() { - return id+"#"+version; - } - public Date getDate() { - return date; - } - public boolean isHTO() { - boolean b = id.startsWith("hl7.terminology.r"); - return b; - } - - } - - public class PackageDetails extends PackageVersion { - private String name; - private String canonical; - private String web; - - public PackageDetails(String id, String version, String name, String canonical, String web, Date date) { - super(id, version, date); - this.name = name; - this.canonical = canonical; - this.web = web; - } - public String getName() { - return name; - } - public String getCanonical() { - return canonical; - } - public String getWeb() { - return web; - } - - } public interface IContextResourceLoader { /** * @return List of the resource types that should be loaded */ String[] getTypes(); - + /** * Request to actually load the resources and do whatever is required * @@ -350,7 +282,7 @@ public interface IWorkerContext { * @throws IOException */ Bundle loadBundle(InputStream stream, boolean isJson) throws FHIRException, IOException; - + /** * Load a single resources (lazy load) * @@ -361,7 +293,7 @@ public interface IWorkerContext { * @throws IOException */ Resource loadResource(InputStream stream, boolean isJson) throws FHIRException, IOException; - + /** * get the path for references to this resource. * @param resource @@ -388,7 +320,7 @@ public interface IWorkerContext { * @return */ public String getVersion(); - + /** * Get the UCUM service that provides access to units of measure reasoning services * @@ -438,6 +370,7 @@ public interface IWorkerContext { */ public T fetchResource(Class class_, String uri); public T fetchResourceWithException(Class class_, String uri) throws FHIRException; + public T fetchResourceWithException(Class class_, String uri, Resource sourceOfReference) throws FHIRException; public T fetchResource(Class class_, String uri, String version); /** has the same functionality as fetchResource, but passes in information about the source of the @@ -449,7 +382,7 @@ public interface IWorkerContext { * @param canonicalForSource * @return */ - public T fetchResource(Class class_, String uri, CanonicalResource canonicalForSource); + public T fetchResource(Class class_, String uri, Resource sourceOfReference); /** * Fetch all the resources of a particular type. if class == (null | Resource | DomainResource | CanonicalResource) return everything @@ -477,7 +410,7 @@ public interface IWorkerContext { * @return */ public Resource fetchResourceById(String type, String uri); - + /** * find whether a resource is available. * @@ -501,7 +434,7 @@ public interface IWorkerContext { * @throws FHIRException */ public void cacheResource(Resource res) throws FHIRException; - + /** * cache a resource for later retrieval using fetchResource. * @@ -514,8 +447,8 @@ public interface IWorkerContext { * @param res * @throws FHIRException */ - public void cacheResourceFromPackage(Resource res, PackageVersion packageDetails) throws FHIRException; - + public void cacheResourceFromPackage(Resource res, PackageInformation packageInfo) throws FHIRException; + /** * Inform the cache about package dependencies. This can be used to help resolve references * @@ -523,10 +456,10 @@ public interface IWorkerContext { * * @param packageInfo */ - public void cachePackage(PackageDetails packageDetails, List dependencies); - + public void cachePackage(PackageInformation packageInfo); + // -- profile services --------------------------------------------------------- - + /** * @return a list of the resource names defined for this version */ @@ -590,7 +523,7 @@ public interface IWorkerContext { * @return */ public ValueSetExpansionOutcome expandVS(ValueSet source, boolean cacheOk, boolean heiarchical); - + /** * ValueSet Expansion - see $expand * @@ -598,7 +531,7 @@ public interface IWorkerContext { * @return */ public ValueSetExpansionOutcome expandVS(ValueSet source, boolean cacheOk, boolean heiarchical, boolean incompleteOk); - + /** * ValueSet Expansion - see $expand, but resolves the binding first * @@ -606,8 +539,8 @@ public interface IWorkerContext { * @return * @throws FHIRException */ - public ValueSetExpansionOutcome expandVS(ElementDefinitionBindingComponent binding, boolean cacheOk, boolean heiarchical) throws FHIRException; - + public ValueSetExpansionOutcome expandVS(Resource src, ElementDefinitionBindingComponent binding, boolean cacheOk, boolean heiarchical) throws FHIRException; + /** * Value set expanion inside the internal expansion engine - used * for references to supported system (see "supportsSystem") for @@ -656,7 +589,7 @@ public interface IWorkerContext { * @return */ public ValidationResult validateCode(ValidationOptions options, String code, ValueSet vs); - + /** * Validation of a code - consult the terminology infrstructure and/or service * to see whether it is known. If known, return a description of it @@ -672,7 +605,7 @@ public interface IWorkerContext { * @return */ public ValidationResult validateCode(ValidationOptions options, String system, String version, String code, String display); - + /** * Validation of a code - consult the terminology infrstructure and/or service * to see whether it is known. If known, return a description of it @@ -723,7 +656,7 @@ public interface IWorkerContext { * @return */ public ValidationResult validateCode(ValidationOptions options, Coding code, ValueSet vs); - + /** * See comments in ValidationContextCarrier. This is called when there might be additional value sets etc * available in the context, but we don't want to pre-process them. @@ -745,10 +678,10 @@ public interface IWorkerContext { * @param vs */ public void validateCodeBatch(ValidationOptions options, List codes, ValueSet vs); - - + + // todo: figure these out - public Map getNSUrlMap(); + public Map getNSUrlMap(); public TranslationServices translator(); public interface ILoggingService { @@ -770,7 +703,7 @@ public interface IWorkerContext { public Set getCodeSystemsUsed(); public int getClientRetryCount(); public IWorkerContext setClientRetryCount(int value); - + public TimeTracker clock(); /** @@ -782,7 +715,7 @@ public interface IWorkerContext { * @return */ public StructureDefinition fetchTypeDefinition(String typeName); - + /** * Returns a set of keys that can be used to get binaries from this context. @@ -849,14 +782,14 @@ public interface IWorkerContext { * @param pcm - used to find and load additional dependencies * @return the number of resources loaded */ - int loadFromPackageAndDependencies(NpmPackage pi, IContextResourceLoader loader, BasePackageCacheManager pcm) throws FileNotFoundException, IOException, FHIRException; + int loadFromPackageAndDependencies(NpmPackage pi, IContextResourceLoader loader, BasePackageCacheManager pcm) throws FileNotFoundException, IOException, FHIRException; - public boolean hasPackage(String id, String ver); - public boolean hasPackage(PackageVersion pack); - public PackageDetails getPackage(PackageVersion pack); + public boolean hasPackage(String id, String ver); + public boolean hasPackage(PackageInformation pack); + public PackageInformation getPackage(String id, String ver); + public PackageInformation getPackageForUrl(String url); public IWorkerContextManager.IPackageLoadingTracker getPackageTracker(); public IWorkerContext setPackageTracker(IWorkerContextManager.IPackageLoadingTracker packageTracker); - public PackageVersion getPackageForUrl(String url); } \ No newline at end of file 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 f046e386a..a02d55c4f 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 @@ -294,7 +294,7 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon return build(context); } - public SimpleWorkerContext fromDefinitions(Map source, IContextResourceLoader loader, PackageVersion pi) throws IOException, FHIRException { + public SimpleWorkerContext fromDefinitions(Map source, IContextResourceLoader loader, PackageInformation pi) throws IOException, FHIRException { SimpleWorkerContext context = getSimpleWorkerContextInstance(); for (String name : source.keySet()) { try { @@ -311,7 +311,7 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon } } - private void loadDefinitionItem(String name, InputStream stream, IContextResourceLoader loader, ILoadFilter filter, PackageVersion pi) throws IOException, FHIRException { + private void loadDefinitionItem(String name, InputStream stream, IContextResourceLoader loader, ILoadFilter filter, PackageInformation pi) throws IOException, FHIRException { if (name.endsWith(".xml")) loadFromFile(stream, name, loader, filter); else if (name.endsWith(".json")) @@ -390,7 +390,7 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon } } - private void loadFromFileJson(InputStream stream, String name, IContextResourceLoader loader, ILoadFilter filter, PackageVersion pi) throws IOException, FHIRException { + private void loadFromFileJson(InputStream stream, String name, IContextResourceLoader loader, ILoadFilter filter, PackageInformation pi) throws IOException, FHIRException { Bundle f = null; try { if (loader != null) @@ -487,7 +487,7 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon } for (String s : pi.listResources(types)) { try { - loadDefinitionItem(s, pi.load("package", s), loader, null, new PackageVersion(pi.id(), pi.version(), pi.dateAsDate())); + loadDefinitionItem(s, pi.load("package", s), loader, null, new PackageInformation(pi)); t++; } catch (Exception e) { throw new FHIRException(formatMessage(I18nConstants.ERROR_READING__FROM_PACKAGE__, s, pi.name(), pi.version(), e.getMessage()), e); @@ -500,7 +500,7 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon for (PackageResourceInformation pri : pi.listIndexedResources(types)) { if (!pri.getFilename().contains("ig-r4")) { try { - registerResourceFromPackage(new PackageResourceLoader(pri, loader), new PackageVersion(pi.id(), pi.version(), pi.dateAsDate())); + registerResourceFromPackage(new PackageResourceLoader(pri, loader), new PackageInformation(pi)); t++; } catch (FHIRException e) { throw new FHIRException(formatMessage(I18nConstants.ERROR_READING__FROM_PACKAGE__, pri.getFilename(), pi.name(), pi.version(), e.getMessage()), e); @@ -672,6 +672,21 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon return r; } + @Override + public T fetchResource(Class class_, String uri, Resource source) { + T r = super.fetchResource(class_, uri, source); + if (r instanceof StructureDefinition) { + StructureDefinition p = (StructureDefinition)r; + try { + new ContextUtilities(this).generateSnapshot(p); + } catch (Exception e) { + // not sure what to do in this case? + System.out.println("Unable to generate snapshot for "+uri+": "+e.getMessage()); + } + } + return r; + } + @@ -706,7 +721,7 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon return xverManager; } - public void cachePackage(PackageVersion packageDetails, List dependencies) { + public void cachePackage(PackageInformation packageInfo) { // nothing yet } @@ -720,17 +735,12 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon } @Override - public void cachePackage(PackageDetails packageDetails, List dependencies) { - // TODO Auto-generated method stub - } - - @Override - public boolean hasPackage(PackageVersion pack) { + public boolean hasPackage(PackageInformation pack) { return false; } @Override - public PackageDetails getPackage(PackageVersion pack) { + public PackageInformation getPackage(String id, String ver) { return null; } 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 1174850fd..01556882a 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 @@ -942,7 +942,7 @@ public class Element extends Base { return null; ICodingImpl c = new ICodingImpl(true, true, false, false); c.code = primitiveValue(); - ValueSetExpansionOutcome vse = property.getContext().expandVS(property.getDefinition().getBinding(), true, false); + ValueSetExpansionOutcome vse = property.getContext().expandVS(property.getStructure(), property.getDefinition().getBinding(), true, false); if (vse.getValueset() == null) return null; for (ValueSetExpansionContainsComponent cc : vse.getValueset().getExpansion().getContains()) { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/PackageInformation.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/PackageInformation.java new file mode 100644 index 000000000..028fddb46 --- /dev/null +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/PackageInformation.java @@ -0,0 +1,99 @@ +package org.hl7.fhir.r5.model; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import org.hl7.fhir.utilities.npm.NpmPackage; + +public class PackageInformation { + private String id; + private String version; + private Date date; + + private String name; + private String canonical; + private String web; + + private List dependencies = new ArrayList<>(); + + public PackageInformation(String id, String version, Date date, String name, String canonical, String web) { + super(); + this.id = id; + this.version = version; + this.date = date; + this.name = name; + this.canonical = canonical; + this.web = web; + } + + public PackageInformation(String src, Date date) { + super(); + this.id = src; + this.date = date; + } + + public PackageInformation(NpmPackage pi) { + super(); + this.id = pi.name(); + this.version = pi.version(); + this.date = pi.dateAsDate(); + this.name = pi.title(); + this.canonical = pi.canonical(); + this.web = pi.getWebLocation(); + dependencies.addAll(pi.dependencies()); + } + + public PackageInformation(String id, String version, Date date) { + super(); + this.id = id; + this.version = version; + this.date = date; + } + + public String getId() { + return id; + } + + public String getVersion() { + return version; + } + + public Date getDate() { + return date; + } + + public String getName() { + return name; + } + + public String getCanonical() { + return canonical; + } + + public String getWeb() { + return web; + } + + public List getDependencies() { + return dependencies; + } + + public boolean isExamplesPackage() { + boolean b = id.startsWith("hl7.fhir.") && id.endsWith(".examples"); + return b; + } + + public boolean isHTO() { + boolean b = id.startsWith("hl7.terminology.r"); + return b; + } + + public String getVID() { + return id+"#"+version; + } + + public String toString() { + return getVID(); + } +} diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/Resource.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/Resource.java index ed181e5ec..9bfe6d0bd 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/Resource.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/Resource.java @@ -446,6 +446,24 @@ public abstract class Resource extends BaseResource implements IAnyResource { public String getLanguage(String defValue) { return hasLanguage() ? getLanguage() : defValue; } + + // when possible, the source package is considered when performing reference resolution. + + private PackageInformation sourcePackage; + + public boolean hasSourcePackage() { + return sourcePackage != null; + } + + public PackageInformation getSourcePackage() { + return sourcePackage; + } + + public void setSourcePackage(PackageInformation sourcePackage) { + this.sourcePackage = sourcePackage; + } + + // end addition } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/openapi/OpenApiGenerator.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/openapi/OpenApiGenerator.java index 469e770d9..44021d685 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/openapi/OpenApiGenerator.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/openapi/OpenApiGenerator.java @@ -50,6 +50,7 @@ import org.hl7.fhir.r5.model.ContactPoint; import org.hl7.fhir.r5.model.ContactPoint.ContactPointSystem; import org.hl7.fhir.r5.model.CapabilityStatement.RestfulCapabilityMode; import org.hl7.fhir.r5.model.Enumerations.SearchParamType; +import org.hl7.fhir.r5.model.Resource; import org.hl7.fhir.r5.model.SearchParameter; import org.hl7.fhir.r5.openapi.ParameterWriter.ParameterLocation; import org.hl7.fhir.r5.openapi.ParameterWriter.ParameterStyle; @@ -84,7 +85,7 @@ public class OpenApiGenerator { for (CapabilityStatementRestComponent csr : source.getRest()) { if (csr.getMode() == RestfulCapabilityMode.SERVER) { - generatePaths(csr); + generatePaths(csr, source); } } writeBaseParameters(dest.components()); @@ -115,21 +116,21 @@ public class OpenApiGenerator { .schema().type(SchemaType.number); } - private void generatePaths(CapabilityStatementRestComponent csr) { + private void generatePaths(CapabilityStatementRestComponent csr, Resource cs) { generateMetadata(); for (CapabilityStatementRestResourceComponent r : csr.getResource()) - generateResource(r); + generateResource(r, cs); if (hasOp(csr, SystemRestfulInteraction.HISTORYSYSTEM)) generateHistorySystem(csr); if (hasOp(csr, SystemRestfulInteraction.SEARCHSYSTEM)) - generateSearchSystem(csr); + generateSearchSystem(csr, cs); if (hasOp(csr, SystemRestfulInteraction.BATCH) || hasOp(csr, SystemRestfulInteraction.TRANSACTION) ) generateBatchTransaction(csr); } - private void generateResource(CapabilityStatementRestResourceComponent r) { + private void generateResource(CapabilityStatementRestResourceComponent r, Resource cs) { if (hasOp(r, TypeRestfulInteraction.SEARCHTYPE)) - generateSearch(r); + generateSearch(r, cs); if (hasOp(r, TypeRestfulInteraction.READ)) generateRead(r); if (hasOp(r, TypeRestfulInteraction.CREATE)) @@ -189,7 +190,7 @@ public class OpenApiGenerator { op.paramRef("#/components/parameters/elements"); } - private void generateSearch(CapabilityStatementRestResourceComponent r) { + private void generateSearch(CapabilityStatementRestResourceComponent r, Resource cs) { OperationWriter op = makePathResType(r).operation("get"); op.summary("Search all resources of type "+r.getType()+" based on a set of criteria"); op.operationId("search"+r.getType()); @@ -213,7 +214,7 @@ public class OpenApiGenerator { p.in(ParameterLocation.query).description(spc.getDocumentation()); p.schema().type(getSchemaType(spc.getType())); if (spc.hasDefinition()) { - SearchParameter sp = context.fetchResource(SearchParameter.class, spc.getDefinition()); + SearchParameter sp = context.fetchResource(SearchParameter.class, spc.getDefinition(), cs); if (sp != null) { p.description(sp.getDescription()); } @@ -222,7 +223,7 @@ public class OpenApiGenerator { } } - private void generateSearchSystem(CapabilityStatementRestComponent csr) { + private void generateSearchSystem(CapabilityStatementRestComponent csr, Resource cs) { OperationWriter op = makePathSystem().operation("get"); op.summary("Search all resources of all types based on a set of criteria"); op.operationId("searchAll"); @@ -250,7 +251,7 @@ public class OpenApiGenerator { p.in(ParameterLocation.query).description(spc.getDocumentation()); p.schema().type(getSchemaType(spc.getType())); if (spc.hasDefinition()) { - SearchParameter sp = context.fetchResource(SearchParameter.class, spc.getDefinition()); + SearchParameter sp = context.fetchResource(SearchParameter.class, spc.getDefinition(), cs); if (sp != null) { p.description(sp.getDescription()); } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ActorDefinitionRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ActorDefinitionRenderer.java index 25ea3de35..47257ddaa 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ActorDefinitionRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ActorDefinitionRenderer.java @@ -50,7 +50,7 @@ public class ActorDefinitionRenderer extends ResourceRenderer { if (acd.hasCapabilities()) { tbl.tr().td().tx("Capabilities:"); td = tr.td().colspan("2"); - CapabilityStatement cs = context.getWorker().fetchResource(CapabilityStatement.class, acd.getCapabilities()); + CapabilityStatement cs = context.getWorker().fetchResource(CapabilityStatement.class, acd.getCapabilities(), acd); if (cs != null) { td.ah(cs.getUserString("path")).tx(cs.present()); } else { @@ -63,7 +63,7 @@ public class ActorDefinitionRenderer extends ResourceRenderer { boolean first = true; for (UrlType t : acd.getReference()) { if (first) first = false; else x.br(); - ActorDefinition df = context.getWorker().fetchResource(ActorDefinition.class, t.getValue()); + ActorDefinition df = context.getWorker().fetchResource(ActorDefinition.class, t.getValue(), acd); if (df != null) { td.ah(df.getUserString("path")).tx(df.present()); } else { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ConceptMapRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ConceptMapRenderer.java index 9fb6b4eff..ef8f00e36 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ConceptMapRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ConceptMapRenderer.java @@ -44,12 +44,12 @@ public class ConceptMapRenderer extends TerminologyRenderer { XhtmlNode p = x.para(); p.tx("Mapping from "); if (cm.hasSourceScope()) - AddVsRef(cm.getSourceScope().primitiveValue(), p); + AddVsRef(cm.getSourceScope().primitiveValue(), p, cm); else p.tx("(not specified)"); p.tx(" to "); if (cm.hasTargetScope()) - AddVsRef(cm.getTargetScope().primitiveValue(), p); + AddVsRef(cm.getTargetScope().primitiveValue(), p, cm); else p.tx("(not specified)"); 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 829580a82..a284c1cf6 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 @@ -763,7 +763,7 @@ public class DataRenderer extends Renderer { } } - protected void renderUri(XhtmlNode x, UriType uri, String path, String id) { + protected void renderUri(XhtmlNode x, UriType uri, String path, String id, Resource src) { if (isCanonical(path)) { x.code().tx(uri.getValue()); } else { @@ -773,7 +773,7 @@ public class DataRenderer extends Renderer { } else if (uri.getValue().startsWith("mailto:")) { x.ah(uri.getValue()).addText(uri.getValue().substring(7)); } else { - Resource target = context.getContext().fetchResource(Resource.class, uri.getValue()); + Resource target = context.getContext().fetchResource(Resource.class, uri.getValue(), src); if (target != null && target.hasUserData("path")) { String title = target instanceof CanonicalResource ? ((CanonicalResource) target).present() : uri.getValue(); x.ah(target.getUserString("path")).addText(title); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/OperationDefinitionRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/OperationDefinitionRenderer.java index 644aee8c9..2563b0750 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/OperationDefinitionRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/OperationDefinitionRenderer.java @@ -52,7 +52,7 @@ public class OperationDefinitionRenderer extends TerminologyRenderer { if (opd.hasInputProfile()) { XhtmlNode p = x.para(); p.tx("Input parameters Profile: "); - StructureDefinition sd = context.getContext().fetchResource(StructureDefinition.class, opd.getInputProfile()); + StructureDefinition sd = context.getContext().fetchResource(StructureDefinition.class, opd.getInputProfile(), opd); if (sd == null) { p.pre().tx(opd.getInputProfile()); } else { @@ -62,7 +62,7 @@ public class OperationDefinitionRenderer extends TerminologyRenderer { if (opd.hasOutputProfile()) { XhtmlNode p = x.para(); p.tx("Output parameters Profile: "); - StructureDefinition sd = context.getContext().fetchResource(StructureDefinition.class, opd.getOutputProfile()); + StructureDefinition sd = context.getContext().fetchResource(StructureDefinition.class, opd.getOutputProfile(), opd); if (sd == null) { p.pre().tx(opd.getOutputProfile()); } else { @@ -79,7 +79,7 @@ public class OperationDefinitionRenderer extends TerminologyRenderer { tr.td().b().tx("Binding"); tr.td().b().tx("Documentation"); for (OperationDefinitionParameterComponent p : opd.getParameter()) { - genOpParam(tbl, "", p); + genOpParam(tbl, "", p, opd); } addMarkdown(x, opd.getComment()); return true; @@ -98,7 +98,7 @@ public class OperationDefinitionRenderer extends TerminologyRenderer { return ((OperationDefinition) r).present(); } - private void genOpParam(XhtmlNode tbl, String path, OperationDefinitionParameterComponent p) throws EOperationOutcome, FHIRException, IOException { + private void genOpParam(XhtmlNode tbl, String path, OperationDefinitionParameterComponent p, Resource opd) throws EOperationOutcome, FHIRException, IOException { XhtmlNode tr; tr = tbl.tr(); tr.td().addText(p.getUse().toString()); @@ -129,13 +129,13 @@ public class OperationDefinitionRenderer extends TerminologyRenderer { } td = tr.td(); if (p.hasBinding() && p.getBinding().hasValueSet()) { - AddVsRef(p.getBinding().getValueSet(), td); + AddVsRef(p.getBinding().getValueSet(), td, opd); td.tx(" ("+p.getBinding().getStrength().getDisplay()+")"); } addMarkdown(tr.td(), p.getDocumentation()); if (!p.hasType()) { for (OperationDefinitionParameterComponent pp : p.getPart()) { - genOpParam(tbl, path+p.getName()+".", pp); + genOpParam(tbl, path+p.getName()+".", pp, opd); } } } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ProfileDrivenRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ProfileDrivenRenderer.java index 3272a5105..5b1da0fb1 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ProfileDrivenRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ProfileDrivenRenderer.java @@ -430,7 +430,7 @@ public class ProfileDrivenRenderer extends ResourceRenderer { renderContactPoint(x, c); } } else if (e instanceof UriType) { - renderUri(x, (UriType) e, defn.getPath(), rcontext != null && rcontext.getResource() != null ? rcontext.getResource().getId() : null); + renderUri(x, (UriType) e, defn.getPath(), rcontext != null && rcontext.getResource() != null ? rcontext.getResource().getId() : null, res.getResource()); } else if (e instanceof Timing) { renderTiming(x, (Timing) e); } else if (e instanceof Range) { @@ -795,7 +795,14 @@ public class ProfileDrivenRenderer extends ResourceRenderer { RenderingContext ctxt = context.copy(); ctxt.setContained(true); ResourceRenderer rnd = RendererFactory.factory(v.fhirType(), ctxt); - ResourceWrapper rw = new ElementWrappers.ResourceWrapperMetaElement(ctxt, (org.hl7.fhir.r5.elementmodel.Element) v.getBase()); + ResourceWrapper rw = null; + if (v.getBase() instanceof org.hl7.fhir.r5.elementmodel.Element) { + rw = new ElementWrappers.ResourceWrapperMetaElement(ctxt, (org.hl7.fhir.r5.elementmodel.Element) v.getBase()); + } else if (v.getBase() instanceof Resource){ + rw = new DirectWrappers.ResourceWrapperDirect(ctxt, (Resource) v.getBase()); + } else { + throw new FHIRException("Not handled: base = "+v.getBase().getClass().getName()); + } rnd.render(x.blockquote(), rw); } } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/QuestionnaireRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/QuestionnaireRenderer.java index e00a11d76..1b15f3a04 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/QuestionnaireRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/QuestionnaireRenderer.java @@ -289,7 +289,7 @@ public class QuestionnaireRenderer extends TerminologyRenderer { if (i.hasDefinition()) { if (!defn.getPieces().isEmpty()) defn.addPiece(gen.new Piece("br")); defn.getPieces().add(gen.new Piece(null, "Definition: ", null)); - genDefinitionLink(gen, i, defn); + genDefinitionLink(gen, i, defn, q); } if (i.hasEnableWhen()) { if (!defn.getPieces().isEmpty()) defn.addPiece(gen.new Piece("br")); @@ -318,7 +318,7 @@ public class QuestionnaireRenderer extends TerminologyRenderer { defn.getPieces().add(gen.new Piece(vs.getUserString("path"), vs.present(), null)); } } else { - ValueSet vs = context.getWorker().fetchResource(ValueSet.class, i.getAnswerValueSet()); + ValueSet vs = context.getWorker().fetchResource(ValueSet.class, i.getAnswerValueSet(), q); if (vs == null || !vs.hasUserData("path")) { defn.getPieces().add(gen.new Piece(null, i.getAnswerValueSet(), null)); } else { @@ -390,7 +390,7 @@ public class QuestionnaireRenderer extends TerminologyRenderer { return hasExt; } - public void genDefinitionLink(HierarchicalTableGenerator gen, QuestionnaireItemComponent i, Cell defn) { + public void genDefinitionLink(HierarchicalTableGenerator gen, QuestionnaireItemComponent i, Cell defn, Questionnaire q) { // can we resolve the definition? String path = null; String d = i.getDefinition(); @@ -398,7 +398,7 @@ public class QuestionnaireRenderer extends TerminologyRenderer { path = d.substring(d.indexOf("#")+1); d = d.substring(0, d.indexOf("#")); } - StructureDefinition sd = context.getWorker().fetchResource(StructureDefinition.class, d); + StructureDefinition sd = context.getWorker().fetchResource(StructureDefinition.class, d, q); if (sd != null) { String url = sd.getUserString("path"); if (url != null) { @@ -411,7 +411,7 @@ public class QuestionnaireRenderer extends TerminologyRenderer { } } - public void genDefinitionLink(XhtmlNode x, QuestionnaireItemComponent i) { + public void genDefinitionLink(XhtmlNode x, QuestionnaireItemComponent i, Questionnaire q) { // can we resolve the definition? String path = null; String d = i.getDefinition(); @@ -419,7 +419,7 @@ public class QuestionnaireRenderer extends TerminologyRenderer { path = d.substring(d.indexOf("#")+1); d = d.substring(0, d.indexOf("#")); } - StructureDefinition sd = context.getWorker().fetchResource(StructureDefinition.class, d); + StructureDefinition sd = context.getWorker().fetchResource(StructureDefinition.class, d, q); if (sd != null) { String url = sd.getUserString("path"); if (url != null) { @@ -479,7 +479,7 @@ public class QuestionnaireRenderer extends TerminologyRenderer { if (i.hasDefinition()) { if (!defn.getPieces().isEmpty()) defn.addPiece(gen.new Piece("br")); defn.getPieces().add(gen.new Piece(null, "Definition: ", null)); - genDefinitionLink(gen, i, defn); + genDefinitionLink(gen, i, defn, q); } if (i.hasEnableWhen()) { if (!defn.getPieces().isEmpty()) defn.addPiece(gen.new Piece("br")); @@ -497,7 +497,7 @@ public class QuestionnaireRenderer extends TerminologyRenderer { defn.getPieces().add(gen.new Piece(vs.getUserString("path"), vs.present(), null)); } } else { - ValueSet vs = context.getWorker().fetchResource(ValueSet.class, i.getAnswerValueSet()); + ValueSet vs = context.getWorker().fetchResource(ValueSet.class, i.getAnswerValueSet(), q); if (vs == null || !vs.hasUserData("path")) { defn.getPieces().add(gen.new Piece(null, i.getAnswerValueSet(), null)); } else { @@ -716,7 +716,7 @@ public class QuestionnaireRenderer extends TerminologyRenderer { item(ul, "Max Length", Integer.toString(i.getMaxLength())); } if (i.hasDefinition()) { - genDefinitionLink(item(ul, "Definition"), i); + genDefinitionLink(item(ul, "Definition"), i, q); } if (i.hasEnableWhen()) { item(ul, "Enable When", "todo"); @@ -731,7 +731,7 @@ public class QuestionnaireRenderer extends TerminologyRenderer { ans.ah(vs.getUserString("path")).tx(vs.present()); } } else { - ValueSet vs = context.getWorker().fetchResource(ValueSet.class, i.getAnswerValueSet()); + ValueSet vs = context.getWorker().fetchResource(ValueSet.class, i.getAnswerValueSet(), q); if (vs == null || !vs.hasUserData("path")) { ans.tx(i.getAnswerValueSet()); } else { @@ -819,7 +819,7 @@ public class QuestionnaireRenderer extends TerminologyRenderer { vs.setUrl(q.getUrl()+"--"+q.getContained(i.getAnswerValueSet().substring(1))); } } else { - vs = context.getContext().fetchResource(ValueSet.class, i.getAnswerValueSet()); + vs = context.getContext().fetchResource(ValueSet.class, i.getAnswerValueSet(), q); } if (vs != null) { ValueSetExpansionOutcome exp = context.getContext().expandVS(vs, true, false); @@ -940,7 +940,7 @@ public class QuestionnaireRenderer extends TerminologyRenderer { // content control defn(tbl, "Max Length", qi.getMaxLength()); if (qi.hasAnswerValueSet()) { - defn(tbl, "Value Set", qi.getDefinition(), context.getWorker().fetchResource(ValueSet.class, qi.getAnswerValueSet())); + defn(tbl, "Value Set", qi.getDefinition(), context.getWorker().fetchResource(ValueSet.class, qi.getAnswerValueSet(), q)); } if (qi.hasAnswerOption()) { XhtmlNode tr = tbl.tr(); @@ -983,7 +983,7 @@ public class QuestionnaireRenderer extends TerminologyRenderer { // formal definitions if (qi.hasDefinition()) { - genDefinitionLink(defn(tbl, "Definition"), qi); + genDefinitionLink(defn(tbl, "Definition"), qi, q); } if (qi.hasCode()) { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/QuestionnaireResponseRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/QuestionnaireResponseRenderer.java index 41505c839..a155e4ed9 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/QuestionnaireResponseRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/QuestionnaireResponseRenderer.java @@ -225,7 +225,7 @@ public class QuestionnaireResponseRenderer extends ResourceRenderer { return hasExt; } - public void genDefinitionLink(HierarchicalTableGenerator gen, QuestionnaireResponseItemComponent i, Cell defn) { + public void genDefinitionLink(HierarchicalTableGenerator gen, QuestionnaireResponseItemComponent i, Cell defn, Resource src) { // can we resolve the definition? String path = null; String d = i.getDefinition(); @@ -233,7 +233,7 @@ public class QuestionnaireResponseRenderer extends ResourceRenderer { path = d.substring(d.indexOf("#")+1); d = d.substring(0, d.indexOf("#")); } - StructureDefinition sd = context.getWorker().fetchResource(StructureDefinition.class, d); + StructureDefinition sd = context.getWorker().fetchResource(StructureDefinition.class, d, src); if (sd != null) { String url = sd.getUserString("path"); if (url != null) { @@ -246,7 +246,7 @@ public class QuestionnaireResponseRenderer extends ResourceRenderer { } } - public void genDefinitionLink(XhtmlNode x, QuestionnaireResponseItemComponent i) { + public void genDefinitionLink(XhtmlNode x, QuestionnaireResponseItemComponent i, Resource src) { // can we resolve the definition? String path = null; String d = i.getDefinition(); @@ -254,7 +254,7 @@ public class QuestionnaireResponseRenderer extends ResourceRenderer { path = d.substring(d.indexOf("#")+1); d = d.substring(0, d.indexOf("#")); } - StructureDefinition sd = context.getWorker().fetchResource(StructureDefinition.class, d); + StructureDefinition sd = context.getWorker().fetchResource(StructureDefinition.class, d, src); if (sd != null) { String url = sd.getUserString("path"); if (url != null) { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/RequirementsRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/RequirementsRenderer.java index 4f53b9188..94900592f 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/RequirementsRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/RequirementsRenderer.java @@ -43,7 +43,7 @@ public class RequirementsRenderer extends ResourceRenderer { public boolean render(XhtmlNode x, Requirements req) throws FHIRFormatError, DefinitionException, IOException { if (req.hasActor()) { if (req.getActor().size() == 1) { - ActorDefinition acd = context.getWorker().fetchResource(ActorDefinition.class, req.getActor().get(0).getValue()); + ActorDefinition acd = context.getWorker().fetchResource(ActorDefinition.class, req.getActor().get(0).getValue(), req); XhtmlNode p = x.para(); p.tx("These requirements apply to the actor "); if (acd == null) { @@ -55,7 +55,7 @@ public class RequirementsRenderer extends ResourceRenderer { x.para().tx("These requirements apply to the following actors:"); XhtmlNode ul = x.ul(); for (CanonicalType a : req.getActor()) { - ActorDefinition acd = context.getWorker().fetchResource(ActorDefinition.class, a.getValue()); + ActorDefinition acd = context.getWorker().fetchResource(ActorDefinition.class, a.getValue(), req); if (acd == null) { ul.li().code(a.getValue()); } else { @@ -66,7 +66,7 @@ public class RequirementsRenderer extends ResourceRenderer { } if (req.hasDerivedFrom()) { if (req.getDerivedFrom().size() == 1) { - Requirements reqd = context.getWorker().fetchResource(Requirements.class, req.getDerivedFrom().get(0).getValue()); + Requirements reqd = context.getWorker().fetchResource(Requirements.class, req.getDerivedFrom().get(0).getValue(), req); XhtmlNode p = x.para(); p.tx("These requirements derive from "); if (reqd == null) { @@ -78,7 +78,7 @@ public class RequirementsRenderer extends ResourceRenderer { x.para().tx("These requirements are derived from the following requirements:"); XhtmlNode ul = x.ul(); for (CanonicalType a : req.getDerivedFrom()) { - Requirements reqd = context.getWorker().fetchResource(Requirements.class, a.getValue()); + Requirements reqd = context.getWorker().fetchResource(Requirements.class, a.getValue(), req); if (reqd == null) { ul.li().code(a.getValue()); } else { @@ -118,7 +118,7 @@ public class RequirementsRenderer extends ResourceRenderer { String url = stmt.getDerivedFrom(); String key = url.contains("#") ? url.substring(url.indexOf("#")+1) : ""; if (url.contains("#")) { url = url.substring(0, url.indexOf("#")); }; - Requirements reqr = context.getWorker().fetchResource(Requirements.class, url); + Requirements reqr = context.getWorker().fetchResource(Requirements.class, url, req); if (reqr != null) { RequirementsStatementComponent stmtr = reqr.findStatement(key); if (stmtr != null) { @@ -140,7 +140,7 @@ public class RequirementsRenderer extends ResourceRenderer { if (url.contains("#")) { url = url.substring(0, url.indexOf("#")); } - Resource r = context.getWorker().fetchResource(Resource.class, url); + Resource r = context.getWorker().fetchResource(Resource.class, url, req); if (r != null) { String desc = getResourceDescription(r, null); li.ah(c.getValue()).tx(desc); @@ -174,7 +174,7 @@ public class RequirementsRenderer extends ResourceRenderer { if (url.contains("#")) { url = url.substring(0, url.indexOf("#")); } - Resource r = context.getWorker().fetchResource(Resource.class, url); + Resource r = context.getWorker().fetchResource(Resource.class, url, req); ResourceWithReference t = null; if (r == null) { t = context.getResolver().resolve(context, url); 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 df7599153..c9d57ba5d 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 @@ -142,14 +142,14 @@ public abstract class ResourceRenderer extends DataRenderer { } public void renderCanonical(ResourceWrapper rw, XhtmlNode x, String url) throws UnsupportedEncodingException, IOException { - renderCanonical(rw, x, url, true); + renderCanonical(rw, x, url, true, rw.getResource()); } - public void renderCanonical(ResourceWrapper rw, XhtmlNode x, String url, boolean allowLinks) throws UnsupportedEncodingException, IOException { + public void renderCanonical(ResourceWrapper rw, XhtmlNode x, String url, boolean allowLinks, Resource src) throws UnsupportedEncodingException, IOException { if (url == null) { return; } - Resource target = context.getWorker().fetchResource(Resource.class, url); + Resource target = context.getWorker().fetchResource(Resource.class, url, src); if (target == null || !(target instanceof CanonicalResource)) { x.code().tx(url); } else { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/SearchParameterRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/SearchParameterRenderer.java index 446a1c1af..768540e24 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/SearchParameterRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/SearchParameterRenderer.java @@ -135,7 +135,7 @@ public class SearchParameterRenderer extends TerminologyRenderer { tbl = x.table("grid"); for (SearchParameterComponentComponent t : spd.getComponent()) { tr = tbl.tr(); - SearchParameter tsp = context.getWorker().fetchResource(SearchParameter.class, t.getDefinition()); + SearchParameter tsp = context.getWorker().fetchResource(SearchParameter.class, t.getDefinition(), spd); if (tsp != null && tsp.hasUserData("path")) { tr.td().ah(tsp.getUserString("path")).tx(tsp.present()); } else { 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 e39f7f48c..b71e465c6 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 @@ -269,7 +269,7 @@ public abstract class TerminologyRenderer extends ResourceRenderer { } - protected void AddVsRef(String value, XhtmlNode li) { + protected void AddVsRef(String value, XhtmlNode li, Resource source) { Resource res = null; if (rcontext != null) { BundleEntryComponent be = rcontext.resolve(value); @@ -283,13 +283,11 @@ public abstract class TerminologyRenderer extends ResourceRenderer { } CanonicalResource vs = (CanonicalResource) res; if (vs == null) - vs = getContext().getWorker().fetchResource(ValueSet.class, value); + vs = getContext().getWorker().fetchResource(ValueSet.class, value, source); if (vs == null) - vs = getContext().getWorker().fetchResource(StructureDefinition.class, value); - // if (vs == null) - // vs = context.getWorker().fetchResource(DataElement.class, value); + vs = getContext().getWorker().fetchResource(StructureDefinition.class, value, source); if (vs == null) - vs = getContext().getWorker().fetchResource(Questionnaire.class, value); + vs = getContext().getWorker().fetchResource(Questionnaire.class, value, source); if (vs != null) { String ref = (String) vs.getUserData("path"); 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 b475568da..951b32474 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 @@ -106,7 +106,7 @@ public class ValueSetRenderer extends TerminologyRenderer { re = new ConceptMapRenderInstructions(cm.present(), cm.getUrl(), false); } if (re != null) { - ValueSet vst = cm.hasTargetScope() ? getContext().getWorker().fetchResource(ValueSet.class, cm.hasTargetScopeCanonicalType() ? cm.getTargetScopeCanonicalType().getValue() : cm.getTargetScopeUriType().asStringValue()) : null; + ValueSet vst = cm.hasTargetScope() ? getContext().getWorker().fetchResource(ValueSet.class, cm.hasTargetScopeCanonicalType() ? cm.getTargetScopeCanonicalType().getValue() : cm.getTargetScopeUriType().asStringValue(), cm) : null; res.add(new UsedConceptMap(re, vst == null ? cm.getUserString("path") : vst.getUserString("path"), cm)); } } @@ -194,8 +194,8 @@ public class ValueSetRenderer extends TerminologyRenderer { x.para().tx("This value set contains "+count.toString()+" concepts"); } - generateContentModeNotices(x, vs.getExpansion()); - generateVersionNotice(x, vs.getExpansion()); + generateContentModeNotices(x, vs.getExpansion(), vs); + generateVersionNotice(x, vs.getExpansion(), vs); CodeSystem allCS = null; boolean doLevel = false; @@ -304,12 +304,12 @@ public class ValueSetRenderer extends TerminologyRenderer { return false; } - private void generateContentModeNotices(XhtmlNode x, ValueSetExpansionComponent expansion) { - generateContentModeNotice(x, expansion, "example", "Expansion based on example code system"); - generateContentModeNotice(x, expansion, "fragment", "Expansion based on code system fragment"); + private void generateContentModeNotices(XhtmlNode x, ValueSetExpansionComponent expansion, Resource vs) { + generateContentModeNotice(x, expansion, "example", "Expansion based on example code system", vs); + generateContentModeNotice(x, expansion, "fragment", "Expansion based on code system fragment", vs); } - private void generateContentModeNotice(XhtmlNode x, ValueSetExpansionComponent expansion, String mode, String text) { + private void generateContentModeNotice(XhtmlNode x, ValueSetExpansionComponent expansion, String mode, String text, Resource vs) { Multimap versions = HashMultimap.create(); for (ValueSetExpansionParameterComponent p : expansion.getParameter()) { if (p.getName().equals(mode)) { @@ -327,7 +327,7 @@ public class ValueSetRenderer extends TerminologyRenderer { for (String v : versions.get(s)) { // though there'll only be one XhtmlNode p = x.para().style("border: black 1px dotted; background-color: #ffcccc; padding: 8px; margin-bottom: 8px"); p.tx(text+" "); - expRef(p, s, v); + expRef(p, s, v, vs); } } else { for (String v : versions.get(s)) { @@ -337,7 +337,7 @@ public class ValueSetRenderer extends TerminologyRenderer { ul = div.ul(); first = false; } - expRef(ul.li(), s, v); + expRef(ul.li(), s, v, vs); } } } @@ -435,7 +435,7 @@ public class ValueSetRenderer extends TerminologyRenderer { } @SuppressWarnings("rawtypes") - private void generateVersionNotice(XhtmlNode x, ValueSetExpansionComponent expansion) { + private void generateVersionNotice(XhtmlNode x, ValueSetExpansionComponent expansion, Resource vs) { Multimap versions = HashMultimap.create(); for (ValueSetExpansionParameterComponent p : expansion.getParameter()) { if (p.getName().equals("version")) { @@ -453,7 +453,7 @@ public class ValueSetRenderer extends TerminologyRenderer { for (String v : versions.get(s)) { // though there'll only be one XhtmlNode p = x.para().style("border: black 1px dotted; background-color: #EEEEEE; padding: 8px; margin-bottom: 8px"); p.tx("Expansion based on "); - expRef(p, s, v); + expRef(p, s, v, vs); } } else { for (String v : versions.get(s)) { @@ -463,14 +463,14 @@ public class ValueSetRenderer extends TerminologyRenderer { ul = div.ul(); first = false; } - expRef(ul.li(), s, v); + expRef(ul.li(), s, v, vs); } } } } } - private void expRef(XhtmlNode x, String u, String v) { + private void expRef(XhtmlNode x, String u, String v, Resource source) { // TODO Auto-generated method stub if (u.equals("http://snomed.info/sct")) { String[] parts = v.split("\\/"); @@ -492,7 +492,7 @@ public class ValueSetRenderer extends TerminologyRenderer { x.tx("Loinc v"+v); } } else { - CanonicalResource cr = (CanonicalResource) getContext().getWorker().fetchResource(Resource.class, u+"|"+v); + CanonicalResource cr = (CanonicalResource) getContext().getWorker().fetchResource(Resource.class, u+"|"+v, source); if (cr != null) { if (cr.hasUserData("path")) { x.ah(cr.getUserString("path")).tx(cr.present()+" v"+v+" ("+cr.fhirType()+")"); @@ -892,13 +892,13 @@ public class ValueSetRenderer extends TerminologyRenderer { } int index = 0; if (vs.getCompose().getInclude().size() == 1 && vs.getCompose().getExclude().size() == 0) { - hasExtensions = genInclude(x.ul(), vs.getCompose().getInclude().get(0), "Include", langs, doDesignations, maps, designations, index) || hasExtensions; + hasExtensions = genInclude(x.ul(), vs.getCompose().getInclude().get(0), "Include", langs, doDesignations, maps, designations, index, vs) || hasExtensions; } else { XhtmlNode p = x.para(); p.tx("This value set includes codes based on the following rules:"); XhtmlNode ul = x.ul(); for (ConceptSetComponent inc : vs.getCompose().getInclude()) { - hasExtensions = genInclude(ul, inc, "Include", langs, doDesignations, maps, designations, index) || hasExtensions; + hasExtensions = genInclude(ul, inc, "Include", langs, doDesignations, maps, designations, index, vs) || hasExtensions; index++; } if (vs.getCompose().hasExclude()) { @@ -906,7 +906,7 @@ public class ValueSetRenderer extends TerminologyRenderer { p.tx("This value set excludes codes based on the following rules:"); ul = x.ul(); for (ConceptSetComponent exc : vs.getCompose().getExclude()) { - hasExtensions = genInclude(ul, exc, "Exclude", langs, doDesignations, maps, designations, index) || hasExtensions; + hasExtensions = genInclude(ul, exc, "Exclude", langs, doDesignations, maps, designations, index, vs) || hasExtensions; index++; } } @@ -1094,7 +1094,7 @@ public class ValueSetRenderer extends TerminologyRenderer { } } - private boolean genInclude(XhtmlNode ul, ConceptSetComponent inc, String type, List langs, boolean doDesignations, List maps, Map designations, int index) throws FHIRException, IOException { + private boolean genInclude(XhtmlNode ul, ConceptSetComponent inc, String type, List langs, boolean doDesignations, List maps, Map designations, int index, Resource vsRes) throws FHIRException, IOException { boolean hasExtensions = false; XhtmlNode li; li = ul.li(); @@ -1228,7 +1228,7 @@ public class ValueSetRenderer extends TerminologyRenderer { first = false; else li.tx(", "); - AddVsRef(vs.asStringValue(), li); + AddVsRef(vs.asStringValue(), li, vsRes); } } if (inc.hasExtension(ToolingExtensions.EXT_EXPAND_RULES) || inc.hasExtension(ToolingExtensions.EXT_EXPAND_GROUP)) { @@ -1244,12 +1244,12 @@ public class ValueSetRenderer extends TerminologyRenderer { first = false; else li.tx(", "); - AddVsRef(vs.asStringValue(), li); + AddVsRef(vs.asStringValue(), li, vsRes); } } else { XhtmlNode xul = li.ul(); for (UriType vs : inc.getValueSet()) { - AddVsRef(vs.asStringValue(), xul.li()); + AddVsRef(vs.asStringValue(), xul.li(), vsRes); } } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/BaseWrappers.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/BaseWrappers.java index 34dc60bfb..67a09994d 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/BaseWrappers.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/BaseWrappers.java @@ -11,6 +11,7 @@ import org.hl7.fhir.r5.model.Base; import org.hl7.fhir.r5.model.ElementDefinition; import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.r5.model.Narrative.NarrativeStatus; +import org.hl7.fhir.r5.model.Resource; import org.hl7.fhir.r5.renderers.ResourceRenderer; import org.hl7.fhir.utilities.xhtml.XhtmlNode; @@ -56,6 +57,7 @@ public class BaseWrappers { public StructureDefinition getDefinition(); public boolean hasNarrative(); public String getNameFromResource(); + public Resource getResource(); // if there is one } public interface BaseWrapper extends WrapperBase { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/DOMWrappers.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/DOMWrappers.java index ee4b11ada..d62204ca6 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/DOMWrappers.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/DOMWrappers.java @@ -11,6 +11,7 @@ import org.hl7.fhir.r5.formats.FormatUtilities; import org.hl7.fhir.r5.model.Base; import org.hl7.fhir.r5.model.ElementDefinition; import org.hl7.fhir.r5.model.Property; +import org.hl7.fhir.r5.model.Resource; import org.hl7.fhir.r5.model.Narrative.NarrativeStatus; import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind; @@ -386,7 +387,7 @@ public class DOMWrappers { if ("DomainResource".equals(sd.getType())) { return true; } - sd = context.getWorker().fetchResource(StructureDefinition.class, sd.getBaseDefinition()); + sd = context.getWorker().fetchResource(StructureDefinition.class, sd.getBaseDefinition(), sd); } return false; } @@ -404,6 +405,11 @@ public class DOMWrappers { return null; } + @Override + public Resource getResource() { + return null; + } + } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/DirectWrappers.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/DirectWrappers.java index a3117b396..6401d5bfe 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/DirectWrappers.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/DirectWrappers.java @@ -295,7 +295,7 @@ public class DirectWrappers { if ("DomainResource".equals(sd.getType())) { return true; } - sd = context.getWorker().fetchResource(StructureDefinition.class, sd.getBaseDefinition()); + sd = context.getWorker().fetchResource(StructureDefinition.class, sd.getBaseDefinition(), sd); } return false; diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/ElementWrappers.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/ElementWrappers.java index e7041c5c3..69b4bd567 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/ElementWrappers.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/ElementWrappers.java @@ -17,6 +17,7 @@ import org.hl7.fhir.r5.formats.IParser.OutputStyle; import org.hl7.fhir.r5.model.Base; import org.hl7.fhir.r5.model.ElementDefinition; import org.hl7.fhir.r5.model.Property; +import org.hl7.fhir.r5.model.Resource; import org.hl7.fhir.r5.model.Narrative.NarrativeStatus; import org.hl7.fhir.r5.model.StringType; import org.hl7.fhir.r5.model.StructureDefinition; @@ -266,7 +267,7 @@ public class ElementWrappers { if ("DomainResource".equals(sd.getType())) { return true; } - sd = context.getWorker().fetchResource(StructureDefinition.class, sd.getBaseDefinition()); + sd = context.getWorker().fetchResource(StructureDefinition.class, sd.getBaseDefinition(), sd); } return false; } @@ -288,6 +289,11 @@ public class ElementWrappers { return wrapped; } + @Override + public Resource getResource() { + return null; + } + } public static class PropertyWrapperMetaElement extends RendererWrapperImpl implements PropertyWrapper { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/ValueSetCheckerSimple.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/ValueSetCheckerSimple.java index ea0ea3006..cb6822889 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/ValueSetCheckerSimple.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/ValueSetCheckerSimple.java @@ -43,7 +43,6 @@ import java.util.Set; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.NoTerminologyServiceException; import org.hl7.fhir.r5.context.IWorkerContext; -import org.hl7.fhir.r5.context.IWorkerContext.PackageVersion; import org.hl7.fhir.r5.context.IWorkerContext.ValidationResult; import org.hl7.fhir.r5.model.CanonicalType; import org.hl7.fhir.r5.model.CodeSystem; @@ -53,6 +52,7 @@ import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionDesignationComponent; import org.hl7.fhir.r5.model.CodeableConcept; import org.hl7.fhir.r5.model.Coding; import org.hl7.fhir.r5.model.Enumerations.PublicationStatus; +import org.hl7.fhir.r5.model.PackageInformation; import org.hl7.fhir.r5.model.UriType; import org.hl7.fhir.r5.model.ValueSet; import org.hl7.fhir.r5.model.ValueSet.ConceptReferenceComponent; @@ -751,7 +751,13 @@ public class ValueSetCheckerSimple extends ValueSetWorker implements ValueSetChe ValidationResult res = context.validateCode(options.noClient(), new Coding(system, code, null), vs); if (res.getErrorClass() == TerminologyServiceErrorClass.UNKNOWN || res.getErrorClass() == TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED || res.getErrorClass() == TerminologyServiceErrorClass.VALUESET_UNSUPPORTED) { if (info != null && res.getErrorClass() == TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED) { + // server didn't know the code system either - we'll take it face value info.getWarnings().add(context.formatMessage(I18nConstants.TERMINOLOGY_TX_SYSTEM_NOTKNOWN, system)); + for (ConceptReferenceComponent cc : vsi.getConcept()) { + if (cc.getCode().equals(code)) { + return true; + } + } info.setErr(TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED); } return null; @@ -786,7 +792,7 @@ public class ValueSetCheckerSimple extends ValueSetWorker implements ValueSetChe } protected boolean isValueSetUnionImports() { - PackageVersion p = (PackageVersion) valueset.getUserData("package"); + PackageInformation p = (PackageInformation) valueset.getSourcePackage(); if (p != null) { return p.getDate().before(new GregorianCalendar(2022, Calendar.MARCH, 31).getTime()); } else { @@ -853,7 +859,7 @@ public class ValueSetCheckerSimple extends ValueSetWorker implements ValueSetChe if (inner.containsKey(url)) { return inner.get(url); } - ValueSet vs = context.fetchResource(ValueSet.class, url); + ValueSet vs = context.fetchResource(ValueSet.class, url, valueset); ValueSetCheckerSimple vsc = new ValueSetCheckerSimple(options, vs, context, localContext); inner.put(url, vsc); return vsc; diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/ValueSetExpanderSimple.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/ValueSetExpanderSimple.java index 0a8b5b973..8accb44a3 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/ValueSetExpanderSimple.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/ValueSetExpanderSimple.java @@ -81,7 +81,6 @@ import org.hl7.fhir.exceptions.FHIRFormatError; import org.hl7.fhir.exceptions.NoTerminologyServiceException; import org.hl7.fhir.exceptions.TerminologyServiceException; import org.hl7.fhir.r5.context.IWorkerContext; -import org.hl7.fhir.r5.context.IWorkerContext.PackageVersion; import org.hl7.fhir.r5.model.BooleanType; import org.hl7.fhir.r5.model.CodeSystem; import org.hl7.fhir.r5.model.CodeSystem.CodeSystemContentMode; @@ -95,6 +94,7 @@ import org.hl7.fhir.r5.model.DateTimeType; import org.hl7.fhir.r5.model.Enumerations.FilterOperator; import org.hl7.fhir.r5.model.Extension; import org.hl7.fhir.r5.model.Factory; +import org.hl7.fhir.r5.model.PackageInformation; import org.hl7.fhir.r5.model.Parameters; import org.hl7.fhir.r5.model.Parameters.ParametersParameterComponent; import org.hl7.fhir.r5.model.PrimitiveType; @@ -508,9 +508,9 @@ public class ValueSetExpanderSimple extends ValueSetWorker implements ValueSetEx private ValueSet importValueSet(String value, ValueSetExpansionComponent exp, Parameters expParams, boolean noInactive, ValueSet valueSet) throws ETooCostly, TerminologyServiceException, FileNotFoundException, IOException, FHIRFormatError { if (value == null) throw fail("unable to find value set with no identity"); - ValueSet vs = context.fetchResource(ValueSet.class, value); + ValueSet vs = context.fetchResource(ValueSet.class, value, valueSet); if (vs == null) { - if (context.fetchResource(CodeSystem.class, value) != null) { + if (context.fetchResource(CodeSystem.class, value, valueSet) != null) { throw fail("Cannot include value set "+value+" because it's actually a code system"); } else { throw fail("Unable to find imported value set " + value); @@ -550,7 +550,7 @@ public class ValueSetExpanderSimple extends ValueSetWorker implements ValueSetEx protected boolean isValueSetUnionImports(ValueSet valueSet) { - PackageVersion p = (PackageVersion) valueSet.getUserData("package"); + PackageInformation p = valueSet.getSourcePackage(); if (p != null) { return p.getDate().before(new GregorianCalendar(2022, Calendar.MARCH, 31).getTime()); } else { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/DefinitionNavigator.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/DefinitionNavigator.java index 645c5f610..773a03051 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/DefinitionNavigator.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/DefinitionNavigator.java @@ -40,6 +40,7 @@ import org.hl7.fhir.exceptions.DefinitionException; import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.model.ElementDefinition; import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent; +import org.hl7.fhir.r5.model.Resource; import org.hl7.fhir.r5.model.StructureDefinition; public class DefinitionNavigator { @@ -164,19 +165,20 @@ public class DefinitionNavigator { * * you have to provide a type if there's more than one type * for current() since this library doesn't know how to choose + * @param res * @throws DefinitionException * @ */ - public boolean hasTypeChildren(TypeRefComponent type) throws DefinitionException { + public boolean hasTypeChildren(TypeRefComponent type, Resource res) throws DefinitionException { if (typeChildren == null || typeOfChildren != type) { - loadTypedChildren(type); + loadTypedChildren(type, res); } return !typeChildren.isEmpty(); } - private void loadTypedChildren(TypeRefComponent type) throws DefinitionException { + private void loadTypedChildren(TypeRefComponent type, Resource src) throws DefinitionException { typeOfChildren = null; - StructureDefinition sd = context.fetchResource(StructureDefinition.class, /* GF#13465 : this somehow needs to be revisited type.hasProfile() ? type.getProfile() : */ type.getWorkingCode()); + StructureDefinition sd = context.fetchResource(StructureDefinition.class, /* GF#13465 : this somehow needs to be revisited type.hasProfile() ? type.getProfile() : */ type.getWorkingCode(), src); if (sd != null) { DefinitionNavigator dn = new DefinitionNavigator(context, sd, 0, path, names, sd.getType()); typeChildren = dn.children(); @@ -187,13 +189,14 @@ public class DefinitionNavigator { /** * + * @param res * @return * @throws DefinitionException * @ */ - public List childrenFromType(TypeRefComponent type) throws DefinitionException { + public List childrenFromType(TypeRefComponent type, Resource res) throws DefinitionException { if (typeChildren == null || typeOfChildren != type) { - loadTypedChildren(type); + loadTypedChildren(type, res); } return typeChildren; } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java index 3443e0363..4615d3348 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java @@ -209,10 +209,12 @@ public class FHIRPathEngine { public static class TypedElementDefinition { private ElementDefinition element; private String type; - public TypedElementDefinition(ElementDefinition element, String type) { + private StructureDefinition src; + public TypedElementDefinition(StructureDefinition src, ElementDefinition element, String type) { super(); this.element = element; this.type = type; + this.src = src; } public TypedElementDefinition(ElementDefinition element) { super(); @@ -245,6 +247,9 @@ public class FHIRPathEngine { return false; } } + public StructureDefinition getSrc() { + return src; + } } private IWorkerContext worker; private IEvaluationContext hostServices; @@ -1812,7 +1817,7 @@ public class FHIRPathEngine { if (tn.equals(sd.getType())) { return makeBoolean(true); } - sd = worker.fetchResource(StructureDefinition.class, sd.getBaseDefinition()); + sd = worker.fetchResource(StructureDefinition.class, sd.getBaseDefinition(), sd); } return makeBoolean(false); } @@ -2992,7 +2997,7 @@ public class FHIRPathEngine { result.add(item); break; } - sd = worker.fetchResource(StructureDefinition.class, sd.getBaseDefinition()); + sd = worker.fetchResource(StructureDefinition.class, sd.getBaseDefinition(), sd); } } } else { @@ -4528,7 +4533,7 @@ public class FHIRPathEngine { if (n.equals(sd.getType())) { return makeBoolean(true); } - sd = worker.fetchResource(StructureDefinition.class, sd.getBaseDefinition()); + sd = worker.fetchResource(StructureDefinition.class, sd.getBaseDefinition(), sd); } return makeBoolean(false); } @@ -4565,7 +4570,7 @@ public class FHIRPathEngine { result.add(b); break; } - sd = worker.fetchResource(StructureDefinition.class, sd.getBaseDefinition()); + sd = worker.fetchResource(StructureDefinition.class, sd.getBaseDefinition(), sd); } } } @@ -5534,7 +5539,7 @@ public class FHIRPathEngine { m = getElementDefinition(sd, type.substring(type.indexOf("#")+1), false, expr); if (m != null && hasDataType(m.definition)) { if (m.fixedType != null) { - StructureDefinition dt = worker.fetchResource(StructureDefinition.class, ProfileUtilities.sdNs(m.fixedType, null)); + StructureDefinition dt = worker.fetchResource(StructureDefinition.class, ProfileUtilities.sdNs(m.fixedType, null), sd); if (dt == null) { throw makeException(expr, I18nConstants.FHIRPATH_NO_TYPE, ProfileUtilities.sdNs(m.fixedType, null), "getChildTypesByName"); } @@ -5693,7 +5698,7 @@ public class FHIRPathEngine { if (ed.getType().size() > 1) { // if there's more than one type, the test above would fail this throw new Error("Internal typing issue...."); } - StructureDefinition nsd = worker.fetchResource(StructureDefinition.class, ProfileUtilities.sdNs(ed.getType().get(0).getCode(), null)); + StructureDefinition nsd = worker.fetchResource(StructureDefinition.class, ProfileUtilities.sdNs(ed.getType().get(0).getCode(), null), sd); if (nsd == null) { throw makeException(expr, I18nConstants.FHIRPATH_NO_TYPE, ed.getType().get(0).getCode(), "getElementDefinition"); } @@ -5808,7 +5813,7 @@ public class FHIRPathEngine { if (element.getTypes().get(0).getTargetProfile().size() > 1) { throw makeExceptionPlural(element.getTypes().get(0).getTargetProfile().size(), expr, I18nConstants.FHIRPATH_RESOLVE_DISCRIMINATOR_NO_TARGET, element.getElement().getId()); } - sd = worker.fetchResource(StructureDefinition.class, element.getTypes().get(0).getTargetProfile().get(0).getValue()); + sd = worker.fetchResource(StructureDefinition.class, element.getTypes().get(0).getTargetProfile().get(0).getValue(), profile); if (sd == null) { throw makeException(expr, I18nConstants.FHIRPATH_RESOLVE_DISCRIMINATOR_CANT_FIND, element.getTypes().get(0).getTargetProfile(), element.getElement().getId()); } @@ -5820,9 +5825,9 @@ public class FHIRPathEngine { if (t.getPath().endsWith(".extension") && t.hasSliceName()) { System.out.println("t: "+t.getId()); StructureDefinition exsd = (t.getType() == null || t.getType().isEmpty() || t.getType().get(0).getProfile().isEmpty()) ? - null : worker.fetchResource(StructureDefinition.class, t.getType().get(0).getProfile().get(0).getValue()); + null : worker.fetchResource(StructureDefinition.class, t.getType().get(0).getProfile().get(0).getValue(), profile); while (exsd != null && !exsd.getBaseDefinition().equals("http://hl7.org/fhir/StructureDefinition/Extension")) { - exsd = worker.fetchResource(StructureDefinition.class, exsd.getBaseDefinition()); + exsd = worker.fetchResource(StructureDefinition.class, exsd.getBaseDefinition(), exsd); } if (exsd != null && exsd.getUrl().equals(targetUrl)) { if (profileUtilities.getChildMap(sd, t).getList().isEmpty()) { @@ -5851,7 +5856,7 @@ public class FHIRPathEngine { okToNotResolve = true; if ((atn.contains(stn))) { if (element.getTypes().size() > 1) { - focus = new TypedElementDefinition(element.getElement(), stn); + focus = new TypedElementDefinition( element.getSrc(), element.getElement(), stn); } else { focus = element; } @@ -5909,9 +5914,9 @@ public class FHIRPathEngine { throw makeExceptionPlural(ed.getTypes().get(0).getProfile().size(), expr, I18nConstants.FHIRPATH_DISCRIMINATOR_MULTIPLE_PROFILES, ed.getElement().getId()); } if (ed.getTypes().get(0).hasProfile()) { - return worker.fetchResource(StructureDefinition.class, ed.getTypes().get(0).getProfile().get(0).getValue()); + return worker.fetchResource(StructureDefinition.class, ed.getTypes().get(0).getProfile().get(0).getValue(), ed.getSrc()); } else { - return worker.fetchResource(StructureDefinition.class, ProfileUtilities.sdNs(ed.getTypes().get(0).getCode(), null)); + return worker.fetchResource(StructureDefinition.class, ProfileUtilities.sdNs(ed.getTypes().get(0).getCode(), null), ed.getSrc()); } } 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 a11fab7a7..6f2840557 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 @@ -1,13 +1,13 @@ package org.hl7.fhir.r5.utils; import org.hl7.fhir.r5.context.CanonicalResourceManager.CanonicalResourceProxy; -import org.hl7.fhir.r5.context.IWorkerContext.PackageVersion; import org.hl7.fhir.r5.model.ElementDefinition; +import org.hl7.fhir.r5.model.PackageInformation; import org.hl7.fhir.r5.model.StructureDefinition; public class PackageHackerR5 { - public static void fixLoadedResource(CanonicalResourceProxy r, PackageVersion packageInfo) { + public static void fixLoadedResource(CanonicalResourceProxy r, PackageInformation packageInfo) { if ("http://terminology.hl7.org/CodeSystem/v2-0391|2.6".equals(r.getUrl())) { r.hack("http://terminology.hl7.org/CodeSystem/v2-0391-2.6", "2.6"); } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/ResourceUtilities.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/ResourceUtilities.java index eea7ba73e..e649a6763 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/ResourceUtilities.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/ResourceUtilities.java @@ -37,6 +37,7 @@ import java.util.Locale; import java.util.Map; import java.util.Set; +import org.hl7.fhir.r5.model.Base; import org.hl7.fhir.r5.model.Bundle; import org.hl7.fhir.r5.model.Bundle.BundleEntryComponent; import org.hl7.fhir.r5.model.Bundle.BundleLinkComponent; @@ -52,6 +53,7 @@ import org.hl7.fhir.r5.model.Meta; 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.model.Property; import org.hl7.fhir.r5.model.Reference; import org.hl7.fhir.r5.model.Resource; import org.hl7.fhir.r5.model.ResourceType; @@ -180,4 +182,28 @@ public class ResourceUtilities { } return b.toString(); } + + public static boolean hasURL(String uri, Resource src) { + for (Property p : src.children()) { + if (hasURL(uri, p)) { + return true; + } + } + return false; + } + + private static boolean hasURL(String uri, Property p) { + for (Base b : p.getValues()) { + if (b.isPrimitive()) { + return uri.equals(b.primitiveValue()); + } else { + for (Property c : b.children()) { + if (hasURL(uri, c)) { + return true; + } + } + } + } + return false; + } } \ No newline at end of file diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/CanonicalResourceManagerTests.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/CanonicalResourceManagerTests.java index 3829e7d07..59c4c4f35 100644 --- a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/CanonicalResourceManagerTests.java +++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/CanonicalResourceManagerTests.java @@ -1,11 +1,13 @@ package org.hl7.fhir.r5.test; +import java.util.ArrayList; import java.util.Date; +import java.util.List; import org.hl7.fhir.r5.context.CanonicalResourceManager; import org.hl7.fhir.r5.context.CanonicalResourceManager.CanonicalResourceProxy; -import org.hl7.fhir.r5.context.IWorkerContext.PackageVersion; import org.hl7.fhir.r5.model.CanonicalResource; +import org.hl7.fhir.r5.model.PackageInformation; import org.hl7.fhir.r5.model.ValueSet; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -428,12 +430,12 @@ public class CanonicalResourceManagerTests { vs2.setVersion("2000.0.0"); vs2.setName("2"); - mrm.see(vs1, new PackageVersion("hl7.fhir.r4.core", "4.0.1", new Date())); + mrm.see(vs1, new PackageInformation("hl7.fhir.r4.core", "4.0.1", new Date())); Assertions.assertNotNull(mrm.get("http://terminology.hl7.org/ValueSet/234")); Assertions.assertNotNull(mrm.get("http://terminology.hl7.org/ValueSet/234", "2.0.0")); Assertions.assertTrue(mrm.get("http://terminology.hl7.org/ValueSet/234").getName().equals("1")); - mrm.see(vs2, new PackageVersion("hl7.terminology.r4", "4.0.1", new Date())); + mrm.see(vs2, new PackageInformation("hl7.terminology.r4", "4.0.1", new Date())); Assertions.assertNotNull(mrm.get("http://terminology.hl7.org/ValueSet/234")); Assertions.assertTrue(mrm.get("http://terminology.hl7.org/ValueSet/234").getName().equals("2")); Assertions.assertNull(mrm.get("http://terminology.hl7.org/ValueSet/234", "2.0.0")); // this will get dropped completely because of UTG rules @@ -809,5 +811,46 @@ public class CanonicalResourceManagerTests { Assertions.assertNull(mrm.get("http://url/ValueSet/234", "4.1")); } + @Test + public void testPackageSpecificResolution1() { + // we add 2 canonicals to the cache with the same identification, but different package information + CanonicalResourceManager mrm = new CanonicalResourceManager<>(false); + ValueSet vs1 = new ValueSet(); + vs1.setId("2345"); + vs1.setUrl("http://url/ValueSet/234"); + vs1.setVersion("4.0.1"); + vs1.setName("1"); + DeferredLoadTestResource vs1d = new DeferredLoadTestResource(vs1); + mrm.see(vs1, new PackageInformation("pid.one", "1.0.0", new Date())); + + ValueSet vs2 = new ValueSet(); + vs2.setId("2346"); + vs2.setUrl("http://url/ValueSet/234"); + vs2.setVersion("4.0.1"); + vs2.setName("2"); + mrm.see(vs2, new PackageInformation("pid.two", "1.0.0", new Date())); + + List pvl1 = new ArrayList<>(); + pvl1.add("pid.one#1.0.0"); + + List pvl2 = new ArrayList<>(); + pvl1.add("pid.two#1.0.0"); + + Assertions.assertEquals("2", mrm.get("http://url/ValueSet/234").getName()); + Assertions.assertEquals("1", mrm.get("http://url/ValueSet/234", pvl1).getName()); + Assertions.assertEquals("2", mrm.get("http://url/ValueSet/234", pvl2).getName()); + + Assertions.assertEquals("2", mrm.get("http://url/ValueSet/234", "4.0.1").getName()); + Assertions.assertEquals("1", mrm.get("http://url/ValueSet/234", "4.0.1", pvl1).getName()); + Assertions.assertEquals("2", mrm.get("http://url/ValueSet/234", "4.0.1", pvl2).getName()); + + Assertions.assertEquals("2", mrm.get("http://url/ValueSet/234", "4.0").getName()); + Assertions.assertEquals("1", mrm.get("http://url/ValueSet/234", "4.0", pvl1).getName()); + Assertions.assertEquals("2", mrm.get("http://url/ValueSet/234", "4.0", pvl2).getName()); + + Assertions.assertEquals("2", mrm.get("http://url/ValueSet/234", "4.0.2").getName()); + Assertions.assertEquals("1", mrm.get("http://url/ValueSet/234", "4.0.2", pvl1).getName()); + Assertions.assertEquals("2", mrm.get("http://url/ValueSet/234", "4.0.2", pvl2).getName()); + } } \ No newline at end of file diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/validation/ValidationMessage.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/validation/ValidationMessage.java index ba6057d25..74a2be7f2 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/validation/ValidationMessage.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/validation/ValidationMessage.java @@ -817,12 +817,13 @@ public class ValidationMessage implements Comparator, Compara return ruleDate; } - public void setRuleDate(Date ruleDate) { + public ValidationMessage setRuleDate(Date ruleDate) { this.ruleDate = ruleDate; + return this; } - public void setRuleDate(String value) { + public ValidationMessage setRuleDate(String value) { if (value == null) { ruleDate = null; } else { @@ -834,5 +835,6 @@ public class ValidationMessage implements Comparator, Compara } ruleDate = d; } + return this; } } \ No newline at end of file diff --git a/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/DateTimeUtilTests.java b/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/DateTimeUtilTests.java index 2a398785c..5cc5ac7d7 100644 --- a/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/DateTimeUtilTests.java +++ b/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/DateTimeUtilTests.java @@ -2,6 +2,7 @@ package org.hl7.fhir.utilities; import static org.junit.jupiter.api.Assertions.assertEquals; +import java.time.ZonedDateTime; import java.util.Date; import java.util.Locale; import java.util.TimeZone; @@ -10,6 +11,7 @@ import java.util.stream.Stream; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; 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 d9e5cee19..558e6701f 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 @@ -801,7 +801,7 @@ public class BaseValidator implements IValidationContextResourceLoader { } - protected ValueSet resolveBindingReference(DomainResource ctxt, String reference, String uri) { + protected ValueSet resolveBindingReference(DomainResource ctxt, String reference, String uri, Resource src) { if (reference != null) { if (reference.equals("http://www.rfc-editor.org/bcp/bcp13.txt")) { reference = "http://hl7.org/fhir/ValueSet/mimetypes"; @@ -814,11 +814,11 @@ public class BaseValidator implements IValidationContextResourceLoader { return null; } else { long t = System.nanoTime(); - ValueSet fr = context.fetchResource(ValueSet.class, reference); + ValueSet fr = context.fetchResource(ValueSet.class, reference, src); if (fr == null) { if (!Utilities.isAbsoluteUrl(reference)) { reference = resolve(uri, reference); - fr = context.fetchResource(ValueSet.class, reference); + fr = context.fetchResource(ValueSet.class, reference, src); } } if (fr == null) { 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 3f7fee206..cf234d386 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 @@ -29,7 +29,6 @@ import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.r5.conformance.ProfileUtilities; import org.hl7.fhir.r5.context.ContextUtilities; import org.hl7.fhir.r5.context.IWorkerContext; -import org.hl7.fhir.r5.context.IWorkerContext.PackageVersion; import org.hl7.fhir.r5.context.IWorkerContextManager; import org.hl7.fhir.r5.context.SimpleWorkerContext; import org.hl7.fhir.r5.context.SystemOutLoggingService; @@ -52,6 +51,7 @@ import org.hl7.fhir.r5.model.ElementDefinition; import org.hl7.fhir.r5.model.ExpressionNode; import org.hl7.fhir.r5.model.ImplementationGuide; import org.hl7.fhir.r5.model.OperationOutcome; +import org.hl7.fhir.r5.model.PackageInformation; import org.hl7.fhir.r5.model.Parameters; import org.hl7.fhir.r5.model.Resource; import org.hl7.fhir.r5.model.StructureDefinition; @@ -429,7 +429,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP if (userAgent != null) { contextBuilder.withUserAgent(userAgent); } - context = contextBuilder.fromDefinitions(source, ValidatorUtils.loaderForVersion(version), new PackageVersion(src, new Date())); + context = contextBuilder.fromDefinitions(source, ValidatorUtils.loaderForVersion(version), new PackageInformation(src, new Date())); ValidatorUtils.grabNatives(getBinaries(), source, "http://hl7.org/fhir"); } // ucum-essence.xml should be in the class path. if it's not, ask about how to sort this out 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 77dd8a370..1775b4a5b 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 @@ -864,7 +864,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat StructureDefinition sd = profiles.get(i); if (sd.hasExtension(ToolingExtensions.EXT_SD_DEPENDENCY)) { for (Extension ext : sd.getExtensionsByUrl(ToolingExtensions.EXT_SD_DEPENDENCY)) { - StructureDefinition dep = context.fetchResource( StructureDefinition.class, ext.getValue().primitiveValue()); + StructureDefinition dep = context.fetchResource( StructureDefinition.class, ext.getValue().primitiveValue(), sd); if (dep == null) { warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, element.line(), element.col(), stack.getLiteralPath(), false, I18nConstants.VALIDATION_VAL_PROFILE_DEPENDS_NOT_RESOLVED, ext.getValue().primitiveValue(), sd.getVersionedUrl()); } else if (!profiles.contains(dep)) { @@ -1025,7 +1025,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat return false; } else { try { - if (context.fetchResourceWithException(ValueSet.class, system) != null) { + if (context.fetchResourceWithException(ValueSet.class, system, element.getProperty().getStructure()) != null) { rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_SYSTEM_VALUESET, system); // Lloyd: This error used to prohibit checking for downstream issues, but there are some cases where that checking needs to occur. Please talk to me before changing the code back. } @@ -1192,7 +1192,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat ElementDefinitionBindingComponent binding = theElementCntext.getBinding(); if (warning(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, binding != null, I18nConstants.TERMINOLOGY_TX_BINDING_MISSING, path)) { if (binding.hasValueSet()) { - ValueSet valueset = resolveBindingReference(profile, binding.getValueSet(), profile.getUrl()); + ValueSet valueset = resolveBindingReference(profile, binding.getValueSet(), profile.getUrl(), profile); if (valueset == null) { CodeSystem cs = context.fetchCodeSystem(binding.getValueSet()); if (rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, cs == null, I18nConstants.TERMINOLOGY_TX_VALUESET_NOTFOUND_CS, describeReference(binding.getValueSet()))) { @@ -1324,7 +1324,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat ElementDefinitionBindingComponent binding = theElementCntext.getBinding(); if (warning(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, binding != null, I18nConstants.TERMINOLOGY_TX_BINDING_MISSING, path)) { if (binding.hasValueSet()) { - ValueSet valueset = resolveBindingReference(profile, binding.getValueSet(), profile.getUrl()); + ValueSet valueset = resolveBindingReference(profile, binding.getValueSet(), profile.getUrl(), profile); if (valueset == null) { CodeSystem cs = context.fetchCodeSystem(binding.getValueSet()); if (rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, cs == null, I18nConstants.TERMINOLOGY_TX_VALUESET_NOTFOUND_CS, describeReference(binding.getValueSet()))) { @@ -1455,7 +1455,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat ElementDefinitionBindingComponent binding = theElementCntext.getBinding(); if (warning(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, binding != null, I18nConstants.TERMINOLOGY_TX_BINDING_MISSING2, path)) { if (binding.hasValueSet()) { - ValueSet valueset = resolveBindingReference(profile, binding.getValueSet(), profile.getUrl()); + ValueSet valueset = resolveBindingReference(profile, binding.getValueSet(), profile.getUrl(), profile); if (valueset == null) { CodeSystem cs = context.fetchCodeSystem(binding.getValueSet()); if (rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, cs == null, I18nConstants.TERMINOLOGY_TX_VALUESET_NOTFOUND_CS, describeReference(binding.getValueSet()))) { @@ -1600,7 +1600,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } private void checkMaxValueSet(List errors, String path, Element element, StructureDefinition profile, String maxVSUrl, CodeableConcept cc, NodeStack stack) { - ValueSet valueset = resolveBindingReference(profile, maxVSUrl, profile.getUrl()); + ValueSet valueset = resolveBindingReference(profile, maxVSUrl, profile.getUrl(), profile); if (valueset == null) { CodeSystem cs = context.fetchCodeSystem(maxVSUrl); if (rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, cs == null, I18nConstants.TERMINOLOGY_TX_VALUESET_NOTFOUND_CS, describeReference(maxVSUrl))) { @@ -1635,7 +1635,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat private boolean checkMaxValueSet(List errors, String path, Element element, StructureDefinition profile, String maxVSUrl, Coding c, NodeStack stack) { boolean ok = true; - ValueSet valueset = resolveBindingReference(profile, maxVSUrl, profile.getUrl()); + ValueSet valueset = resolveBindingReference(profile, maxVSUrl, profile.getUrl(), profile); if (valueset == null) { CodeSystem cs = context.fetchCodeSystem(maxVSUrl); if (rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, cs == null, I18nConstants.TERMINOLOGY_TX_VALUESET_NOTFOUND_CS, describeReference(maxVSUrl))) { @@ -1664,7 +1664,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat private boolean checkMaxValueSet(List errors, String path, Element element, StructureDefinition profile, String maxVSUrl, String value, NodeStack stack) { boolean ok = true; - ValueSet valueset = resolveBindingReference(profile, maxVSUrl, profile.getUrl()); + ValueSet valueset = resolveBindingReference(profile, maxVSUrl, profile.getUrl(), profile); if (valueset == null) { CodeSystem cs = context.fetchCodeSystem(maxVSUrl); if (rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, cs == null, I18nConstants.TERMINOLOGY_TX_VALUESET_NOTFOUND_CS, describeReference(maxVSUrl))) { @@ -1732,7 +1732,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat ElementDefinitionBindingComponent binding = theElementCntext.getBinding(); if (warning(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, binding != null, I18nConstants.TERMINOLOGY_TX_BINDING_MISSING2, path)) { if (binding.hasValueSet()) { - ValueSet valueset = resolveBindingReference(profile, binding.getValueSet(), profile.getUrl()); + ValueSet valueset = resolveBindingReference(profile, binding.getValueSet(), profile.getUrl(), profile); if (valueset == null) { CodeSystem cs = context.fetchCodeSystem(binding.getValueSet()); if (rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, cs == null, I18nConstants.TERMINOLOGY_TX_VALUESET_NOTFOUND_CS, describeReference(binding.getValueSet()))) { @@ -1977,7 +1977,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat break; } if (sd.getBaseDefinition() != null) { - sd = context.fetchResource(StructureDefinition.class, sd.getBaseDefinition()); + sd = context.fetchResource(StructureDefinition.class, sd.getBaseDefinition(), sd); } else { sd = null; } @@ -2533,7 +2533,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } else { boolean tok = false; for (StructureDefinition t : context.fetchResourcesByType(StructureDefinition.class)) { - if (t.hasUserData("package") && t.getUserString("package").startsWith("hl7.fhir.r") && v.equals(t.getType())) { + if (t.hasSourcePackage() && t.getSourcePackage().getId().startsWith("hl7.fhir.r") && v.equals(t.getType())) { tok = true; } } @@ -2921,7 +2921,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat // firstly, resolve the value set ElementDefinitionBindingComponent binding = elementContext.getBinding(); if (binding.hasValueSet()) { - ValueSet vs = resolveBindingReference(profile, binding.getValueSet(), profile.getUrl()); + ValueSet vs = resolveBindingReference(profile, binding.getValueSet(), profile.getUrl(), profile); if (vs == null) { CodeSystem cs = context.fetchCodeSystem(binding.getValueSet()); if (rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, cs == null, I18nConstants.TERMINOLOGY_TX_VALUESET_NOTFOUND_CS, describeReference(binding.getValueSet()))) { @@ -3442,7 +3442,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat StructureDefinition sdFT = context.fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/"+ft); boolean rok = false; for (CanonicalType tp : type.getTargetProfile()) { - StructureDefinition sd = context.fetchResource(StructureDefinition.class, tp.getValue()); + StructureDefinition sd = context.fetchResource(StructureDefinition.class, tp.getValue(), profile); if (sd != null) { types.add(sd.getType()); } @@ -3452,7 +3452,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat rok = true; break; } - sdF = sdF.hasBaseDefinition() ? context.fetchResource(StructureDefinition.class, sdF.getBaseDefinition()) : null; + sdF = sdF.hasBaseDefinition() ? context.fetchResource(StructureDefinition.class, sdF.getBaseDefinition(), sdF) : null; } } ok = rule(errors, NO_RULE_DATE, IssueType.STRUCTURE, element.line(), element.col(), path, types.isEmpty() || rok, @@ -3758,7 +3758,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat for (TypeRefComponent type : element.getType()) { for (CanonicalType p : type.getProfile()) { String id = p.hasExtension(ToolingExtensions.EXT_PROFILE_ELEMENT) ? p.getExtensionString(ToolingExtensions.EXT_PROFILE_ELEMENT) : null; - StructureDefinition sd = context.fetchResource(StructureDefinition.class, p.getValue()); + StructureDefinition sd = context.fetchResource(StructureDefinition.class, p.getValue(), profile); if (sd == null) throw new DefinitionException(context.formatMessage(I18nConstants.UNABLE_TO_RESOLVE_PROFILE_, p)); profile = sd; @@ -3801,13 +3801,13 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat return igs; } - private StructureDefinition getProfileForType(String type, List list) { + private StructureDefinition getProfileForType(String type, List list, Resource src) { for (TypeRefComponent tr : list) { String url = tr.getWorkingCode(); if (!Utilities.isAbsoluteUrl(url)) url = "http://hl7.org/fhir/StructureDefinition/" + url; long t = System.nanoTime(); - StructureDefinition sd = context.fetchResource(StructureDefinition.class, url); + StructureDefinition sd = context.fetchResource(StructureDefinition.class, url, src); timeTracker.sd(t); if (sd != null && (sd.getType().equals(type) || sd.getUrl().equals(type)) && sd.hasSnapshot()) { return sd; @@ -4196,7 +4196,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat return null; } else { long t = System.nanoTime(); - StructureDefinition fr = context.fetchResource(StructureDefinition.class, pr); + StructureDefinition fr = context.fetchResource(StructureDefinition.class, pr, profile); timeTracker.sd(t); return fr; } @@ -4800,7 +4800,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat for (ImplementationGuide ig : igs) { for (ImplementationGuideGlobalComponent gl : ig.getGlobal()) { if (rt.equals(gl.getType())) { - StructureDefinition sd = context.fetchResource(StructureDefinition.class, gl.getProfile()); + StructureDefinition sd = context.fetchResource(StructureDefinition.class, gl.getProfile(), ig); if (warning(errors, NO_RULE_DATE, IssueType.STRUCTURE, element.line(), element.col(), stack.getLiteralPath(), sd != null, I18nConstants.VALIDATION_VAL_GLOBAL_PROFILE_UNKNOWN, gl.getProfile())) { if (crumbTrails) { element.addMessage(signpost(errors, NO_RULE_DATE, IssueType.INFORMATIONAL, element.line(), element.col(), stack.getLiteralPath(), I18nConstants.VALIDATION_VAL_PROFILE_SIGNPOST_GLOBAL, sd.getVersionedUrl(), ig.getVersionedUrl())); @@ -5132,7 +5132,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (typeForResource.getProfile().size() == 1) { long t = System.nanoTime(); - StructureDefinition profile = this.context.fetchResource(StructureDefinition.class, typeForResource.getProfile().get(0).asStringValue()); + StructureDefinition profile = this.context.fetchResource(StructureDefinition.class, typeForResource.getProfile().get(0).asStringValue(), parentProfile); timeTracker.sd(t); trackUsage(profile, hostContext, element); if (rule(errors, NO_RULE_DATE, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), @@ -5165,7 +5165,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } else { List types = new ArrayList<>(); for (UriType u : typeForResource.getProfile()) { - StructureDefinition sd = this.context.fetchResource(StructureDefinition.class, u.getValue()); + StructureDefinition sd = this.context.fetchResource(StructureDefinition.class, u.getValue(), parentProfile); if (sd != null && !types.contains(sd.getType())) { types.add(sd.getType()); } @@ -5210,7 +5210,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } } } - sdt = context.fetchResource(StructureDefinition.class, sdt.getBaseDefinition()); + sdt = context.fetchResource(StructureDefinition.class, sdt.getBaseDefinition(), sdt); } return false; } @@ -5533,7 +5533,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat String tail = null; if (profiles.isEmpty()) { if (type != null) { - p = getProfileForType(type, checkDefn.getType()); + p = getProfileForType(type, checkDefn.getType(), profile); // If dealing with a primitive type, then we need to check the current child against // the invariants (constraints) on the current element, because otherwise it only gets @@ -5550,7 +5550,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat tail = url.substring(url.indexOf("#") + 1); url = url.substring(0, url.indexOf("#")); } - p = this.context.fetchResource(StructureDefinition.class, url); + p = this.context.fetchResource(StructureDefinition.class, url, profile); ok = rule(errors, NO_RULE_DATE, IssueType.STRUCTURE, ei.line(), ei.col(), ei.getPath(), p != null, I18nConstants.VALIDATION_VAL_UNKNOWN_PROFILE, profiles.get(0)) && ok; } else { elementValidated = true; @@ -6020,7 +6020,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat return false; } while (profile != null) { - profile = context.fetchResource(StructureDefinition.class, profile.getBaseDefinition()); + profile = context.fetchResource(StructureDefinition.class, profile.getBaseDefinition(), profile); if (profile != null) { if (source.equals(profile.getUrl())) { return true; diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/QuestionnaireValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/QuestionnaireValidator.java index 6c68bc679..c70a3598f 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/QuestionnaireValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/QuestionnaireValidator.java @@ -546,7 +546,7 @@ public class QuestionnaireValidator extends BaseValidator { if (ref.startsWith("#") && qSrc.container != null) { vs = (ValueSet) loadContainedResource(errors, qSrc.containerPath, qSrc.container, ref.substring(1), ValueSet.class); } else { - vs = resolveBindingReference(qSrc.q(), ref, qSrc.q().getUrl()); + vs = resolveBindingReference(qSrc.q(), ref, qSrc.q().getUrl(), qSrc.q()); } if (warning(errors, NO_RULE_DATE, IssueType.CODEINVALID, value.line(), value.col(), stack.getLiteralPath(), vs != null, I18nConstants.TERMINOLOGY_TX_VALUESET_NOTFOUND, describeReference(ref))) { try { diff --git a/pom.xml b/pom.xml index ef93c1adb..09f1f74a0 100644 --- a/pom.xml +++ b/pom.xml @@ -19,7 +19,7 @@ 5.4.0 - 1.1.127 + 1.1.128-SNAPSHOT 5.7.1 1.8.2 3.0.0-M5