Merge pull request #491 from hapifhir/gg-202105-bugfixes-2

* Validator: Load code systems from known packages on the fly
This commit is contained in:
Grahame Grieve 2021-05-07 21:36:47 +10:00 committed by GitHub
commit 5a11851ec7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 83 additions and 13 deletions

View File

@ -3,6 +3,12 @@
* Snapshot generator: fix problem checking types on logical models * Snapshot generator: fix problem checking types on logical models
* Do not flag internal references as suspicious * Do not flag internal references as suspicious
* XMLParser allows passing a schema location * XMLParser allows passing a schema location
* XMLParser allows passing a schema location
* Issue 484 https://github.com/hapifhir/org.hl7.fhir.core/issues/484 * Issue 484 https://github.com/hapifhir/org.hl7.fhir.core/issues/484
* Adding Kotlin to the build process * Adding Kotlin to the build process
* random cleaning up in convertors * random cleaning up in convertors
* Validator: Load code systems from known packages on the fly
* Validator: better handle invalid v3 dates
* Renderer: Render OperationDefinition.InputProfile and OutputProfile
* Important: Allow more valid schemas for Utilities.isAbsoluteUrl
* Validator: remove notes about extensible bindings if profile extensible binding is valid

View File

@ -267,7 +267,7 @@ public class StructureMap30_50 {
VersionConvertor_30_50.copyElement(src, tgt); VersionConvertor_30_50.copyElement(src, tgt);
if (src.hasContext()) if (src.hasContext())
tgt.setContextElement(VersionConvertor_30_50.convertId(src.getContextElement())); tgt.setContextElement(VersionConvertor_30_50.convertId(src.getContextElement()));
if (src.hasContextType() && src.getContextType() == org.hl7.fhir.dstu3.model.StructureMap.StructureMapContextType.VARIABLE) if (src.hasContextType() && src.getContextType() != org.hl7.fhir.dstu3.model.StructureMap.StructureMapContextType.VARIABLE)
throw new Error("This conversion is not supported. Consult code maintainers"); // this should never happens - no one knows what the intent was here. throw new Error("This conversion is not supported. Consult code maintainers"); // this should never happens - no one knows what the intent was here.
if (src.hasElement()) if (src.hasElement())
tgt.setElementElement(VersionConvertor_30_50.convertString(src.getElementElement())); tgt.setElementElement(VersionConvertor_30_50.convertString(src.getElementElement()));

View File

@ -205,6 +205,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
protected TerminologyCache txCache; protected TerminologyCache txCache;
protected TimeTracker clock; protected TimeTracker clock;
private boolean tlogging = true; private boolean tlogging = true;
private ICanonicalResourceLocator locator;
public BaseWorkerContext() throws FileNotFoundException, IOException, FHIRException { public BaseWorkerContext() throws FileNotFoundException, IOException, FHIRException {
txCache = new TerminologyCache(lock, null); txCache = new TerminologyCache(lock, null);
@ -498,9 +499,17 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
@Override @Override
public CodeSystem fetchCodeSystem(String system) { public CodeSystem fetchCodeSystem(String system) {
CodeSystem cs;
synchronized (lock) { synchronized (lock) {
return codeSystems.get(system); cs = codeSystems.get(system);
} }
if (cs == null && locator != null) {
locator.findResource(system);
synchronized (lock) {
cs = codeSystems.get(system);
}
}
return cs;
} }
@Override @Override
@ -2002,4 +2011,12 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
} }
} }
public ICanonicalResourceLocator getLocator() {
return locator;
}
public void setLocator(ICanonicalResourceLocator locator) {
this.locator = locator;
}
} }

View File

@ -170,6 +170,10 @@ public interface IWorkerContext {
} }
} }
public interface ICanonicalResourceLocator {
void findResource(String url); // if it can be found, put it in the context
}
public interface IContextResourceLoader { public interface IContextResourceLoader {
/** /**
* @return List of the resource types that shoud be loaded * @return List of the resource types that shoud be loaded

View File

@ -468,8 +468,12 @@ public class XmlParser extends ParserBase {
private String convertForDateFormatFromExternal(String fmt, String av) throws FHIRException { private String convertForDateFormatFromExternal(String fmt, String av) throws FHIRException {
if ("v3".equals(fmt)) { if ("v3".equals(fmt)) {
try {
DateTimeType d = DateTimeType.parseV3(av); DateTimeType d = DateTimeType.parseV3(av);
return d.asStringValue(); return d.asStringValue();
} catch (Exception e) {
return av; // not at all clear what to do in this case.
}
} else } else
throw new FHIRException(context.formatMessage(I18nConstants.UNKNOWN_DATA_FORMAT_, fmt)); throw new FHIRException(context.formatMessage(I18nConstants.UNKNOWN_DATA_FORMAT_, fmt));
} }

View File

@ -50,6 +50,26 @@ public class OperationDefinitionRenderer extends TerminologyRenderer {
x.para().tx("URL: [base]/"+c.getValue()+"/[id]/$"+opd.getCode()); x.para().tx("URL: [base]/"+c.getValue()+"/[id]/$"+opd.getCode());
} }
if (opd.hasInputProfile()) {
XhtmlNode p = x.para();
p.tx("Input parameters Profile: ");
StructureDefinition sd = context.getContext().fetchResource(StructureDefinition.class, opd.getInputProfile());
if (sd == null) {
p.pre().tx(opd.getInputProfile());
} else {
p.ah(sd.getUserString("path")).tx(sd.present());
}
}
if (opd.hasOutputProfile()) {
XhtmlNode p = x.para();
p.tx("Output parameters Profile: ");
StructureDefinition sd = context.getContext().fetchResource(StructureDefinition.class, opd.getOutputProfile());
if (sd == null) {
p.pre().tx(opd.getOutputProfile());
} else {
p.ah(sd.getUserString("path")).tx(sd.present());
}
}
x.para().tx("Parameters"); x.para().tx("Parameters");
XhtmlNode tbl = x.table( "grid"); XhtmlNode tbl = x.table( "grid");
XhtmlNode tr = tbl.tr(); XhtmlNode tr = tbl.tr();

View File

@ -1093,10 +1093,12 @@ public class Utilities {
public static boolean isAbsoluteUrl(String ref) { public static boolean isAbsoluteUrl(String ref) {
return ref != null && (ref.startsWith("http:") || ref.startsWith("https:") || ref.startsWith("urn:uuid:") || ref.startsWith("urn:oid:") || if (ref != null && ref.contains(":")) {
Utilities.startsWithInList(ref, "urn:iso:", "urn:iso-iec:", "urn:iso-cie:", "urn:iso-astm:", "urn:iso-ieee:", "urn:iec:")); // rfc5141 String scheme = ref.substring(0, ref.indexOf(":"));
return existsInList(scheme, "http", "https", "urn") || isToken(scheme) || Utilities.startsWithInList(ref, "urn:iso:", "urn:iso-iec:", "urn:iso-cie:", "urn:iso-astm:", "urn:iso-ieee:", "urn:iec:"); // rfc5141
}
return false;
} }
public static boolean equivalent(String l, String r) { public static boolean equivalent(String l, String r) {
if (Utilities.noString(l) && Utilities.noString(r)) if (Utilities.noString(l) && Utilities.noString(r))

View File

@ -814,7 +814,7 @@ public class NpmPackage {
// } // }
public String getWebLocation() { public String getWebLocation() {
if (npm.has("url")) { if (npm.has("url") && npm.get("url").isJsonPrimitive()) {
return PackageHacker.fixPackageUrl(npm.get("url").getAsString()); return PackageHacker.fixPackageUrl(npm.get("url").getAsString());
} else { } else {
return JSONUtil.str(npm, "canonical"); return JSONUtil.str(npm, "canonical");

View File

@ -833,7 +833,7 @@ public class BaseValidator {
String targetUrl = null; String targetUrl = null;
String version = ""; String version = "";
String resourceType = null; String resourceType = null;
if (ref.startsWith("http") || ref.startsWith("urn")) { if (ref.startsWith("http:") || ref.startsWith("urn:") || Utilities.isAbsoluteUrl(ref)) {
// We've got an absolute reference, no need to calculate // We've got an absolute reference, no need to calculate
if (ref.contains("/_history/")) { if (ref.contains("/_history/")) {
targetUrl = ref.substring(0, ref.indexOf("/_history/") - 1); targetUrl = ref.substring(0, ref.indexOf("/_history/") - 1);

View File

@ -9,6 +9,7 @@ import org.hl7.fhir.convertors.txClient.TerminologyClientFactory;
import org.hl7.fhir.exceptions.DefinitionException; import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r5.conformance.ProfileUtilities; import org.hl7.fhir.r5.conformance.ProfileUtilities;
import org.hl7.fhir.r5.context.IWorkerContext.ICanonicalResourceLocator;
import org.hl7.fhir.r5.context.IWorkerContext.PackageVersion; import org.hl7.fhir.r5.context.IWorkerContext.PackageVersion;
import org.hl7.fhir.r5.context.SimpleWorkerContext; import org.hl7.fhir.r5.context.SimpleWorkerContext;
import org.hl7.fhir.r5.elementmodel.Element; import org.hl7.fhir.r5.elementmodel.Element;
@ -134,6 +135,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst
@Getter @Setter private PrintWriter mapLog; @Getter @Setter private PrintWriter mapLog;
@Getter @Setter private boolean debug = false; @Getter @Setter private boolean debug = false;
@Getter @Setter private IValidatorResourceFetcher fetcher; @Getter @Setter private IValidatorResourceFetcher fetcher;
@Getter @Setter private ICanonicalResourceLocator locator;
@Getter @Setter private boolean assumeValidRestReferences; @Getter @Setter private boolean assumeValidRestReferences;
@Getter @Setter private boolean noExtensibleBindingMessages; @Getter @Setter private boolean noExtensibleBindingMessages;
@Getter @Setter private boolean securityChecks; @Getter @Setter private boolean securityChecks;

View File

@ -4,6 +4,7 @@ import com.google.gson.JsonObject;
import org.hl7.fhir.convertors.txClient.TerminologyClientFactory; import org.hl7.fhir.convertors.txClient.TerminologyClientFactory;
import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.context.IWorkerContext.ICanonicalResourceLocator;
import org.hl7.fhir.r5.elementmodel.Element; import org.hl7.fhir.r5.elementmodel.Element;
import org.hl7.fhir.r5.model.CanonicalResource; import org.hl7.fhir.r5.model.CanonicalResource;
import org.hl7.fhir.r5.terminologies.TerminologyClient; import org.hl7.fhir.r5.terminologies.TerminologyClient;
@ -26,7 +27,7 @@ import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
public class StandAloneValidatorFetcher implements IValidatorResourceFetcher { public class StandAloneValidatorFetcher implements IValidatorResourceFetcher, ICanonicalResourceLocator {
List<String> mappingsUris = new ArrayList<>(); List<String> mappingsUris = new ArrayList<>();
private FilesystemPackageCacheManager pcm; private FilesystemPackageCacheManager pcm;
@ -63,7 +64,7 @@ public class StandAloneValidatorFetcher implements IValidatorResourceFetcher {
url = url.substring(0, url.lastIndexOf("|")); url = url.substring(0, url.lastIndexOf("|"));
} }
if (type.equals("uri") && isMappingUri(url)) { if (type != null && type.equals("uri") && isMappingUri(url)) {
return true; return true;
} }
@ -128,6 +129,7 @@ public class StandAloneValidatorFetcher implements IValidatorResourceFetcher {
pidMap.put(pid+"|"+ver, null); pidMap.put(pid+"|"+ver, null);
} }
if (pi != null) { if (pi != null) {
context.loadFromPackage(pi, null);
return pi.hasCanonical(url); return pi.hasCanonical(url);
} }
} }
@ -249,4 +251,12 @@ public class StandAloneValidatorFetcher implements IValidatorResourceFetcher {
return true; return true;
} }
@Override
public void findResource(String url) {
try {
resolveURL(null, null, url, null);
} catch (Exception e) {
}
}
} }

View File

@ -246,7 +246,9 @@ public class ValidationService {
validator.setSecurityChecks(cliContext.isSecurityChecks()); validator.setSecurityChecks(cliContext.isSecurityChecks());
validator.setCrumbTrails(cliContext.isCrumbTrails()); validator.setCrumbTrails(cliContext.isCrumbTrails());
validator.setShowTimes(cliContext.isShowTimes()); validator.setShowTimes(cliContext.isShowTimes());
validator.setFetcher(new StandAloneValidatorFetcher(validator.getPcm(), validator.getContext(), validator)); StandAloneValidatorFetcher fetcher = new StandAloneValidatorFetcher(validator.getPcm(), validator.getContext(), validator);
validator.setFetcher(fetcher);
validator.getContext().setLocator(fetcher);
validator.getBundleValidationRules().addAll(cliContext.getBundleValidationRules()); validator.getBundleValidationRules().addAll(cliContext.getBundleValidationRules());
TerminologyCache.setNoCaching(cliContext.isNoInternalCaching()); TerminologyCache.setNoCaching(cliContext.isNoInternalCaching());
validator.prepare(); // generate any missing snapshots validator.prepare(); // generate any missing snapshots

View File

@ -1052,6 +1052,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
res = false; res = false;
txWarning(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, vr.getMessage()); txWarning(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, vr.getMessage());
} else { } else {
if (binding.getStrength() == BindingStrength.EXTENSIBLE) {
removeTrackedMessagesForLocation(errors, element, path);
}
res = false; res = false;
} }
} }

View File

@ -19,7 +19,7 @@
<properties> <properties>
<hapi_fhir_version>5.1.0</hapi_fhir_version> <hapi_fhir_version>5.1.0</hapi_fhir_version>
<validator_test_case_version>1.1.62</validator_test_case_version> <validator_test_case_version>1.1.63-SNAPSHOT</validator_test_case_version>
<junit_jupiter_version>5.7.1</junit_jupiter_version> <junit_jupiter_version>5.7.1</junit_jupiter_version>
<junit_platform_launcher_version>1.7.1</junit_platform_launcher_version> <junit_platform_launcher_version>1.7.1</junit_platform_launcher_version>
<maven_surefire_version>3.0.0-M4</maven_surefire_version> <maven_surefire_version>3.0.0-M4</maven_surefire_version>