Merge pull request #1179 from hapifhir/gg-202303-various-fixes

Gg 202303 various fixes
This commit is contained in:
Grahame Grieve 2023-03-21 07:37:43 +11:00 committed by GitHub
commit 102fc366dd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 139 additions and 29 deletions

View File

@ -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<String> types = new ArrayList<>();
protected ILoaderKnowledgeProviderR5 lkp;
private boolean loadProfiles = true;
public BaseLoaderR5(List<String> 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;
}
}
}

View File

@ -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));
}

View File

@ -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);
}
/**

View File

@ -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++;

View File

@ -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"));
}

View File

@ -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
}

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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());
}

View File

@ -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()));
}
}

View File

@ -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);

View File

@ -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<Element> 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 {
}
}
}
}
}
}

View File

@ -19,7 +19,7 @@
<properties>
<hapi_fhir_version>6.2.1</hapi_fhir_version>
<validator_test_case_version>1.2.21</validator_test_case_version>
<validator_test_case_version>1.2.22-SNAPSHOT</validator_test_case_version>
<junit_jupiter_version>5.7.1</junit_jupiter_version>
<junit_platform_launcher_version>1.8.2</junit_platform_launcher_version>
<maven_surefire_version>3.0.0-M5</maven_surefire_version>