diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/loaderR5/BaseLoaderR5.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/loaderR5/BaseLoaderR5.java index 5e6d83f58..5d8a08726 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/loaderR5/BaseLoaderR5.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/loaderR5/BaseLoaderR5.java @@ -24,6 +24,7 @@ import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.VersionUtilities; import org.hl7.fhir.utilities.npm.NpmPackage; +import org.hl7.fhir.utilities.npm.NpmPackage.PackageResourceInformation; import com.google.gson.JsonSyntaxException; @@ -40,6 +41,7 @@ public abstract class BaseLoaderR5 implements IContextResourceLoader { @Getter @Setter protected boolean killPrimitives; @Getter protected List types = new ArrayList<>(); protected ILoaderKnowledgeProviderR5 lkp; + private boolean loadProfiles = true; public BaseLoaderR5(List types, ILoaderKnowledgeProviderR5 lkp) { super(); @@ -169,6 +171,12 @@ public abstract class BaseLoaderR5 implements IContextResourceLoader { String url = URL_BASE+versionString()+"/StructureDefinition/"+code; ToolingExtensions.setUrlExtension(tr, ToolingExtensions.EXT_FHIR_TYPE, url); } + for (CanonicalType c : tr.getProfile()) { + c.setValue(patchUrl(c.getValue(), "StructureDefinition")); + } + for (CanonicalType c : tr.getTargetProfile()) { + c.setValue(patchUrl(c.getValue(), "StructureDefinition")); + } } if (ed.hasBinding()) { ed.getBinding().setValueSet(patchUrl(ed.getBinding().getValueSet(), "ValueSet")); @@ -178,4 +186,20 @@ public abstract class BaseLoaderR5 implements IContextResourceLoader { } } + public IContextResourceLoader setLoadProfiles(boolean value) { + loadProfiles = value; + return this; + } + + public boolean wantLoad(NpmPackage pi, PackageResourceInformation pri) { + if (pri.getResourceType().equals("StructureDefinition")) { + if (loadProfiles) { + return true; + } else { + return pi.isCore() && Utilities.tail(pri.getUrl()).equals(pri.getStatedType()); + } + } else { + return true; + } + } } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfileUtilities.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfileUtilities.java index be4e6a328..29b0de37a 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfileUtilities.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfileUtilities.java @@ -661,10 +661,7 @@ public class ProfileUtilities extends TranslatingUtilities { System.out.println(" "+ed.getId()+" = "+ed.getPath()+" : "+typeSummaryWithProfile(ed)+"["+ed.getMin()+".."+ed.getMax()+"]"+sliceSummary(ed)+" "+constraintSummary(ed)); } } - if (exception) - throw new DefinitionException(msg); - else - messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE, url, msg, ValidationMessage.IssueSeverity.ERROR)); + handleError(url, msg); } // hack around a problem in R4 definitions (somewhere?) for (ElementDefinition ed : derived.getSnapshot().getElement()) { @@ -712,14 +709,20 @@ public class ProfileUtilities extends TranslatingUtilities { if (ed.getPath().equals("Bundle.entry.response.outcome")) { wt = "OperationOutcome"; } - if (!sd.getType().equals(wt)) { - boolean ok = isCompatibleType(wt, sd); + String tt = sd.getType(); + boolean elementProfile = u.hasExtension(ToolingExtensions.EXT_PROFILE_ELEMENT); + if (elementProfile) { + ElementDefinition edt = sd.getSnapshot().getElementById(u.getExtensionString(ToolingExtensions.EXT_PROFILE_ELEMENT)); + if (edt == null) { + handleError(url, "The profile "+u.getValue()+" has type "+sd.getType()+" which is not consistent with the stated type "+wt); + } else { + tt = edt.typeSummary(); + } + } + if (!tt.equals(wt)) { + boolean ok = !elementProfile && isCompatibleType(wt, sd); if (!ok) { - String smsg = "The profile "+u.getValue()+" has type "+sd.getType()+" which is not consistent with the stated type "+wt; - if (exception) - throw new DefinitionException(smsg); - else - messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE, url+"#"+ed.getId(), smsg, IssueSeverity.ERROR)); + handleError(url, "The profile "+u.getValue()+" has type "+sd.getType()+" which is not consistent with the stated type "+wt); } } } @@ -738,6 +741,13 @@ public class ProfileUtilities extends TranslatingUtilities { } } + private void handleError(String url, String msg) { + if (exception) + throw new DefinitionException(msg); + else + messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE, url, msg, ValidationMessage.IssueSeverity.ERROR)); + } + 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 88523f6b2..7de49a2cd 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 @@ -77,6 +77,7 @@ import org.hl7.fhir.utilities.TimeTracker; import org.hl7.fhir.utilities.TranslationServices; import org.hl7.fhir.utilities.npm.BasePackageCacheManager; import org.hl7.fhir.utilities.npm.NpmPackage; +import org.hl7.fhir.utilities.npm.NpmPackage.PackageResourceInformation; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity; import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.utilities.validation.ValidationOptions; @@ -338,6 +339,23 @@ public interface IWorkerContext { * @return */ String patchUrl(String url, String resourceType); + + /** + * set this to false (default is true) if you don't want profiles loaded + * @param value + * @return + */ + IContextResourceLoader setLoadProfiles(boolean value); + + /** + * Called during the loading process - the loader can decide which resources to load. + * At this point, only the .index.json is being read + * + * @param pi + * @param pri + * @return + */ + boolean wantLoad(NpmPackage pi, PackageResourceInformation pri); } /** 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 66d2a9dae..a8935689f 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 @@ -492,7 +492,7 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon types = Utilities.strings("StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire", "ConceptMap", "StructureMap", "NamingSystem", "Measures" ); } for (PackageResourceInformation pri : pi.listIndexedResources(types)) { - if (!pri.getFilename().contains("ig-r4")) { + if (!pri.getFilename().contains("ig-r4") && (loader == null || loader.wantLoad(pi, pri))) { try { registerResourceFromPackage(new PackageResourceLoader(pri, loader), new PackageInformation(pi)); t++; diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/FmlParser.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/FmlParser.java index 463264666..53bf2ac76 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/FmlParser.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/FmlParser.java @@ -394,7 +394,7 @@ public class FmlParser extends ParserBase { if (rule.getChildrenByName("source").size() != 1 || !rule.getChildrenByName("source").get(0).hasChild("element")) throw lexer.error("Complex rules must have an explicit name"); if (rule.getChildrenByName("source").get(0).hasChild("type")) - rule.makeElement("name").setValue(rule.getChildrenByName("source").get(0).getNamedChildValue("element") + rule.getChildrenByName("source").get(0).getNamedChildValue("type")); + rule.makeElement("name").setValue(rule.getChildrenByName("source").get(0).getNamedChildValue("element") + Utilities.capitalize(rule.getChildrenByName("source").get(0).getNamedChildValue("type"))); else rule.makeElement("name").setValue(rule.getChildrenByName("source").get(0).getNamedChildValue("element")); } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/StructureDefinition.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/StructureDefinition.java index 0861ad248..0d532e830 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/StructureDefinition.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/StructureDefinition.java @@ -1245,6 +1245,20 @@ public class StructureDefinition extends CanonicalResource { return null; } + + public ElementDefinition getElementById(String id) { + if (id == null) { + return null; + } + for (ElementDefinition ed : getElement()) { + if (id.equals(ed.getId())) { + return ed; + } + } + return null; + } + + // end addition } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/StructureMapRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/StructureMapRenderer.java index 4c1dfd2de..0c3ce0b96 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/StructureMapRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/StructureMapRenderer.java @@ -461,7 +461,7 @@ public class StructureMapRenderer extends TerminologyRenderer { if (n.equals(s) || n.equals("\"" + s + "\"")) return true; if (source.get(0).hasType()) { - s = source.get(0).getElement() + "-" + source.get(0).getType(); + s = source.get(0).getElement() + Utilities.capitalize(source.get(0).getType()); return n.equals(s) || n.equals("\"" + s + "\""); } return false; diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/test/utils/TestPackageLoader.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/test/utils/TestPackageLoader.java index e0a5871b5..c3e68dd96 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/test/utils/TestPackageLoader.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/test/utils/TestPackageLoader.java @@ -13,6 +13,7 @@ import org.hl7.fhir.r5.model.Bundle; import org.hl7.fhir.r5.model.CodeSystem; import org.hl7.fhir.r5.model.Resource; import org.hl7.fhir.utilities.npm.NpmPackage; +import org.hl7.fhir.utilities.npm.NpmPackage.PackageResourceInformation; public class TestPackageLoader implements IContextResourceLoader { @@ -62,4 +63,14 @@ public class TestPackageLoader implements IContextResourceLoader { return url; } + @Override + public IContextResourceLoader setLoadProfiles(boolean value) { + return this; + } + + @Override + public boolean wantLoad(NpmPackage pi, PackageResourceInformation pri) { + return true; + } + } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/structuremap/StructureMapUtilities.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/structuremap/StructureMapUtilities.java index 2e59bd557..ff619d56b 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/structuremap/StructureMapUtilities.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/structuremap/StructureMapUtilities.java @@ -1000,7 +1000,7 @@ public class StructureMapUtilities { if (rule.getSource().size() != 1 || !rule.getSourceFirstRep().hasElement() && exceptionsForChecks ) throw lexer.error("Complex rules must have an explicit name"); if (rule.getSourceFirstRep().hasType()) - rule.setName(rule.getSourceFirstRep().getElement() + "-" + rule.getSourceFirstRep().getType()); + rule.setName(rule.getSourceFirstRep().getElement() + Utilities.capitalize(rule.getSourceFirstRep().getType())); else rule.setName(rule.getSourceFirstRep().getElement()); } diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/Utilities.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/Utilities.java index 57961ee09..3eb3b14d2 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/Utilities.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/Utilities.java @@ -1543,10 +1543,13 @@ public class Utilities { ZipEntry zipEntry = zis.getNextEntry(); while (zipEntry != null) { boolean isDirectory = false; - if (zipEntry.getName().endsWith("/") || zipEntry.getName().endsWith("\\")) { + + String n = makeOSSafe(zipEntry.getName()); + + if (n.endsWith(File.separator)) { isDirectory = true; } - Path newPath = zipSlipProtect(zipEntry, target); + Path newPath = zipSlipProtect(n, target); if (isDirectory) { Files.createDirectories(newPath); } else { @@ -1563,19 +1566,23 @@ public class Utilities { } } - public static Path zipSlipProtect(ZipEntry zipEntry, Path targetDir) + public static String makeOSSafe(String name) { + return name.replace("\\", File.separator).replace("/", File.separator); + } + + public static Path zipSlipProtect(String zipName, Path targetDir) throws IOException { // test zip slip vulnerability // Path targetDirResolved = targetDir.resolve("../../" + zipEntry.getName()); - Path targetDirResolved = targetDir.resolve(zipEntry.getName()); + Path targetDirResolved = targetDir.resolve(zipName); // make sure normalized file still has targetDir as its prefix // else throws exception Path normalizePath = targetDirResolved.normalize(); if (!normalizePath.startsWith(targetDir)) { - throw new IOException("Bad zip entry: " + zipEntry.getName()); + throw new IOException("Bad zip entry: " + zipName); } return normalizePath; @@ -1920,7 +1927,7 @@ public class Utilities { if (ignoreList == null || !ignoreList.contains(f.getAbsolutePath())) { if (f.isDirectory()) { addAllFiles(res, root, f, ignoreList); - } else { + } else if (!f.getName().equals(".DS_Store")) { res.add(getRelativePath(root, f.getAbsolutePath())); } } 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 cc678f7c5..be22270cc 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 @@ -2646,7 +2646,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (fetcher != null && !type.equals("uuid")) { boolean found; try { - found = isDefinitionURL(url) || (allowExamples && (url.contains("example.org") || url.contains("acme.com")) || url.contains("acme.org")) || (url.startsWith("http://hl7.org/fhir/tools")) || + found = isDefinitionURL(url) || (allowExamples && (url.contains("example.org") || url.contains("acme.com")) || url.contains("acme.org")) /* || (url.startsWith("http://hl7.org/fhir/tools")) */ || SpecialExtensions.isKnownExtension(url) || isXverUrl(url); if (!found) { found = fetcher.resolveURL(this, hostContext, path, url, type); diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/StructureMapValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/StructureMapValidator.java index 602467b63..302898026 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/StructureMapValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/StructureMapValidator.java @@ -199,6 +199,11 @@ public class StructureMapValidator extends BaseValidator { return sd.getUrl().equals(other.sd.getUrl()) && ed.getPath().equals(other.ed.getPath()) && Utilities.stringsEqual(type, other.type); } + @Override + public String toString() { + return summary(); + } + } public class VariableSet { @@ -623,11 +628,17 @@ public class StructureMapValidator extends BaseValidator { } else { ok = false; } + // check condition + // check check } - // check condition - // check check + } else { + String variable = source.getChildValue("variable"); + if (variable != null) { + variables.add(variable, v.getMode()); // may overwrite + + } } - } + } return ok; } @@ -873,20 +884,34 @@ public class StructureMapValidator extends BaseValidator { // under some special conditions, we can infer what the type will be: // * there's a nominated default variable // * that variable has as single type - // * there's a create with no param + // * there's a create/copy with no param // * there's a single dependent rule with name = StructureMapUtilities.DEF_GROUP_NAME - // * there's a default type group for the type of the source type + // * there's a default type group for the type of the source type // otherwise, we can't know the target type. if (ruleInfo.getDefVariable() != null && Utilities.existsInList(transform, "create", "copy") && params.isEmpty()) { VariableDefn v = variables.getVariable(ruleInfo.getDefVariable(), SOURCE); if (v != null && v.getEd() != null && (v.getEd().getType().size() == 1 || v.getType() != null)) { List dependents = rule.getChildrenByName("dependent"); + String type = v.getType() != null ? getTypeFromDefn(v.getEd(), v.getType()) : v.getEd().getTypeFirstRep().getWorkingCode(); if (dependents.size() == 1 && StructureMapUtilities.DEF_GROUP_NAME.equals(dependents.get(0).getChildValue("name"))) { - String type = v.getType() != null ? getTypeFromDefn(v.getEd(), v.getType()) : v.getEd().getTypeFirstRep().getWorkingCode(); // now, we look for a default group. // todo: look in this source // now look through the inputs + for (StructureMap map : imports) { + for (StructureMapGroupComponent grp : map.getGroup()) { + if (grp.getTypeMode() != StructureMapGroupTypeMode.NULL && grp.getInput().size() == 2) { + String grpType = getTypeForGroupInput(map, grp, grp.getInput().get(0)); + if (sameTypes(type, grpType)) { + String tgtType = getTypeForGroupInput(map, grp, grp.getInput().get(1)); + if (tgtType != null) { + return tgtType; + } + } + } + } + } + } else if (dependents.size() == 0) { for (StructureMap map : imports) { for (StructureMapGroupComponent grp : map.getGroup()) { if (grp.getTypeMode() == StructureMapGroupTypeMode.TYPEANDTYPES && grp.getInput().size() == 2) { @@ -900,6 +925,7 @@ public class StructureMapValidator extends BaseValidator { } } } + } } } diff --git a/pom.xml b/pom.xml index 3c49e7407..c37f2223a 100644 --- a/pom.xml +++ b/pom.xml @@ -19,7 +19,7 @@ 6.2.1 - 1.2.21 + 1.2.22-SNAPSHOT 5.7.1 1.8.2 3.0.0-M5