* 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
This commit is contained in:
Grahame Grieve 2021-05-07 18:29:21 +10:00
parent b13b4932f9
commit 4e173f4715
14 changed files with 83 additions and 14 deletions

View File

@ -3,3 +3,8 @@
* Snapshot generator: fix problem checking types on logical models
* Do not flag internal references as suspicious
* XMLParser allows passing a schema location
* 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);
if (src.hasContext())
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.
if (src.hasElement())
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 TimeTracker clock;
private boolean tlogging = true;
private ICanonicalResourceLocator locator;
public BaseWorkerContext() throws FileNotFoundException, IOException, FHIRException {
txCache = new TerminologyCache(lock, null);
@ -498,9 +499,17 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
@Override
public CodeSystem fetchCodeSystem(String system) {
CodeSystem cs;
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
@ -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 {
/**
* @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 {
if ("v3".equals(fmt)) {
DateTimeType d = DateTimeType.parseV3(av);
return d.asStringValue();
try {
DateTimeType d = DateTimeType.parseV3(av);
return d.asStringValue();
} catch (Exception e) {
return av; // not at all clear what to do in this case.
}
} else
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());
}
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");
XhtmlNode tbl = x.table( "grid");
XhtmlNode tr = tbl.tr();

View File

@ -1093,11 +1093,13 @@ public class Utilities {
public static boolean isAbsoluteUrl(String ref) {
return ref != null && (ref.startsWith("http:") || ref.startsWith("https:") || ref.startsWith("urn:uuid:") || ref.startsWith("urn:oid:") ||
Utilities.startsWithInList(ref, "urn:iso:", "urn:iso-iec:", "urn:iso-cie:", "urn:iso-astm:", "urn:iso-ieee:", "urn:iec:")); // rfc5141
if (ref != null && ref.contains(":")) {
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) {
if (Utilities.noString(l) && Utilities.noString(r))
return true;

View File

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

View File

@ -833,7 +833,7 @@ public class BaseValidator {
String targetUrl = null;
String version = "";
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
if (ref.contains("/_history/")) {
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.FHIRException;
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.SimpleWorkerContext;
import org.hl7.fhir.r5.elementmodel.Element;
@ -138,6 +139,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst
@Getter @Setter private PrintWriter mapLog;
@Getter @Setter private boolean debug = false;
@Getter @Setter private IValidatorResourceFetcher fetcher;
@Getter @Setter private ICanonicalResourceLocator locator;
@Getter @Setter private boolean assumeValidRestReferences;
@Getter @Setter private boolean noExtensibleBindingMessages;
@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.exceptions.FHIRException;
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.model.CanonicalResource;
import org.hl7.fhir.r5.terminologies.TerminologyClient;
@ -26,7 +27,7 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
public class StandAloneValidatorFetcher implements IValidatorResourceFetcher {
public class StandAloneValidatorFetcher implements IValidatorResourceFetcher, ICanonicalResourceLocator {
List<String> mappingsUris = new ArrayList<>();
private FilesystemPackageCacheManager pcm;
@ -63,7 +64,7 @@ public class StandAloneValidatorFetcher implements IValidatorResourceFetcher {
url = url.substring(0, url.lastIndexOf("|"));
}
if (type.equals("uri") && isMappingUri(url)) {
if (type != null && type.equals("uri") && isMappingUri(url)) {
return true;
}
@ -128,6 +129,7 @@ public class StandAloneValidatorFetcher implements IValidatorResourceFetcher {
pidMap.put(pid+"|"+ver, null);
}
if (pi != null) {
context.loadFromPackage(pi, null);
return pi.hasCanonical(url);
}
}
@ -249,4 +251,12 @@ public class StandAloneValidatorFetcher implements IValidatorResourceFetcher {
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.setCrumbTrails(cliContext.isCrumbTrails());
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());
TerminologyCache.setNoCaching(cliContext.isNoInternalCaching());
validator.prepare(); // generate any missing snapshots

View File

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

View File

@ -19,7 +19,7 @@
<properties>
<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_platform_launcher_version>1.7.1</junit_platform_launcher_version>
<maven_surefire_version>3.0.0-M4</maven_surefire_version>