#820 Add warnings when potential matches are found when performing reference resolution in bundles

This commit is contained in:
Grahame Grieve 2022-05-27 13:43:19 +10:00
parent 655fc8b6ca
commit 12a1dbfc05
11 changed files with 120 additions and 16 deletions

View File

@ -701,6 +701,9 @@ public class I18nConstants {
public static final String TYPE_SPECIFIC_CHECKS_DT_BASE64_NO_WS_ERROR = "TYPE_SPECIFIC_CHECKS_DT_BASE64_NO_WS_ERROR";
public static final String TYPE_SPECIFIC_CHECKS_DT_BASE64_NO_WS_WARNING = "TYPE_SPECIFIC_CHECKS_DT_BASE64_NO_WS_WARNING";
public static final String TX_SERVER_NO_BATCH_RESPONSE = "TX_SERVER_NO_BATCH_RESPONSE";
public static final String BUNDLE_POSSSIBLE_MATCHES = "BUNDLE_POSSSIBLE_MATCHES";
public static final String BUNDLE_BUNDLE_POSSIBLE_MATCH_NO_FU = "BUNDLE_BUNDLE_POSSIBLE_MATCH_NO_FU";
public static final String BUNDLE_BUNDLE_POSSIBLE_MATCH_WRONG_FU = "BUNDLE_BUNDLE_POSSIBLE_MATCH_WRONG_FU";
}

View File

@ -851,6 +851,9 @@ public class NpmPackage {
public InputStream loadExampleResource(String type, String id) throws IOException {
NpmPackageFolder f = folders.get("example");
if (f == null) {
f = folders.get("package/example");
}
if (f != null) {
JsonArray files = f.index.getAsJsonArray("files");
for (JsonElement e : files) {

View File

@ -108,7 +108,7 @@ public class BaseTestingUtilities {
}
public static String tempFolder(String name) throws IOException {
String path = ToolGlobalSettings.hasTempPath() ? ToolGlobalSettings.getTempPath() : Utilities.path("[tmp]", name);
String path = Utilities.path(ToolGlobalSettings.hasTempPath() ? ToolGlobalSettings.getTempPath() : "[tmp]", name);
Utilities.createDirectory(path);
return path;
}

View File

@ -111,7 +111,7 @@ Reference_REF_BadTargetType = Invalid Resource target type. Found {0}, but expec
Reference_REF_BadTargetType2 = The type ''{0}'' implied by the reference URL {1} is not a valid Target for this element (must be one of {2})
Reference_REF_CantMatchChoice = Unable to find a match for profile {0} among choices: {1}
Reference_REF_CantMatchType = Unable to find a match for profile {0} (by type) among choices: {1}
Reference_REF_CantResolve = Unable to resolve resource ''{0}''
Reference_REF_CantResolve = Unable to resolve resource with reference ''{0}''
Reference_REF_CantResolveProfile = Unable to resolve the profile reference ''{0}''
Reference_REF_Format1 = Relative URLs must be of the format [ResourceName]/[id], or a search URL is allowed ([type]?parameters. Encountered {0})
Reference_REF_Format2 = Relative URLs must be of the format [ResourceName]/[id]. Encountered {0}
@ -280,7 +280,7 @@ Unable_to_locate_the_profile__in_order_to_validate_against_it = Unable to locate
Reference__refers_to_a__not_a_ValueSet = Reference {0} refers to a {1} not a ValueSet
Not_done_yet_ValidatorHostServicesconformsToProfile_when_item_is_not_an_element = Not done yet (ValidatorHostServices.conformsToProfile), when item is not an element
Not_supported_yet = Not supported yet
Unable_to_resolve_ = Unable to resolve {0}
Unable_to_resolve_ = Unable to resolve the reference {0}
Not_done_yet__resolve__locally_2 = Not done yet - resolve {0} locally (2)
Not_done_yet_ValidatorHostServicesexecuteFunction = Not done yet (ValidatorHostServices.executeFunction)
Not_done_yet_ValidatorHostServicescheckFunction = Not done yet (ValidatorHostServices.checkFunction)
@ -711,3 +711,6 @@ TYPE_SPECIFIC_CHECKS_DT_BASE64_NO_WS_WARNING = Base64 encoded values SHOULD not
SD_DERIVATION_KIND_MISMATCH = The structure definition constrains a kind of {0}, but has a different kind ({1})
VALUESET_IMPORT_UNION_INTERSECTION = This value set has a single include with multiple imported value sets. Per issue https://jira.hl7.org/browse/FHIR-25179, there has been confusion in the past whether these value sets are unioned or intersectioned. If this value set is contained in a package published prior to March 31 2022, it will be treated as a union, otherwise it will be treated as an intersection. If want a union, split the value set imports across multiple includes
TX_SERVER_NO_BATCH_RESPONSE = The server return null from a batch validation request
BUNDLE_POSSSIBLE_MATCHES = The bundle contains no match for {1} by the rules of Bundle reference resolution, but it has multiple resources that match {0} by resource type and id
BUNDLE_BUNDLE_POSSIBLE_MATCH_NO_FU = Entry {0} matches the reference {1} by type and id but it does not match the full target URL {2} by Bundle resolution rules
BUNDLE_BUNDLE_POSSIBLE_MATCH_WRONG_FU = Entry {0} matches the reference {1} by type and id but it''s fullUrl {2} does not match the full target URL {3} by Bundle resolution rules

View File

@ -950,8 +950,34 @@ public class BaseValidator implements IValidationContextResourceLoader {
if (match != null && resourceType != null)
rule(errors, IssueType.REQUIRED, -1, -1, path, match.getType().equals(resourceType), I18nConstants.REFERENCE_REF_RESOURCETYPE, ref, match.getType());
if (match == null)
if (match == null) {
warning(errors, IssueType.REQUIRED, -1, -1, path, !ref.startsWith("urn"), I18nConstants.BUNDLE_BUNDLE_NOT_LOCAL, ref);
if (!Utilities.isAbsoluteUrl(ref)) {
String[] p = ref.split("\\/");
List<Element> ml = new ArrayList<>();
if (p.length >= 2 && Utilities.existsInList(p[0], context.getResourceNames()) && Utilities.isValidId(p[1])) {
for (int i = 0; i < entries.size(); i++) {
Element we = entries.get(i);
Element r = we.getNamedChild(RESOURCE);
if (r != null && p[0].equals(r.fhirType()) && p[1].equals(r.getNamedChildValue("id")) ) {
ml.add(we);
}
}
}
if (ml.size() > 1) {
warning(errors, IssueType.REQUIRED, -1, -1, path, false, I18nConstants.BUNDLE_POSSSIBLE_MATCHES, ref, targetUrl);
}
for (Element e : ml) {
String fu = e.getChildValue(FULL_URL);
int i = entries.indexOf(e);
if (fu == null) {
warning(errors, IssueType.REQUIRED, -1, -1, path, false, I18nConstants.BUNDLE_BUNDLE_POSSIBLE_MATCH_NO_FU, i, ref, targetUrl);
} else {
warning(errors, IssueType.REQUIRED, -1, -1, path, false, I18nConstants.BUNDLE_BUNDLE_POSSIBLE_MATCH_WRONG_FU, i, ref, fu, targetUrl);
}
}
}
}
return match == null ? null : new IndexedElement(matchIndex, match, entries.get(matchIndex));
}

View File

@ -627,6 +627,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
igLoader.loadIg(getIgs(), getBinaries(), SHCParser.CURRENT_PACKAGE, true);
}
validator.setJurisdiction(jurisdiction);
validator.setLogProgress(true);
return validator;
}

View File

@ -60,7 +60,7 @@ public class ComparisonService {
public static void compareStructureDefinitions(String dest, ValidationEngine validator, String left, String right, StructureDefinition resLeft, StructureDefinition resRight) throws IOException, FHIRException, EOperationOutcome {
System.out.println("Comparing StructureDefinitions " + left + " to " + right);
ComparisonSession session = new ComparisonSession(validator.getContext(), validator.getContext(), "Comparing Profiles", null);
ComparisonSession session = new ComparisonSession(validator.getContext(), validator.getContext(), "Comparing Profiles", null, null);
session.compare(resLeft, resRight);
System.out.println("Generating output to " + dest + "...");

View File

@ -424,6 +424,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
private QuestionnaireMode questionnaireMode;
private ValidationOptions baseOptions = new ValidationOptions();
private Map<String, CanonicalResourceLookupResult> crLookups = new HashMap<>();
private boolean logProgress;
public InstanceValidator(IWorkerContext theContext, IEvaluationContext hostServices, XVerExtensionManager xverManager) {
super(theContext, xverManager);
@ -2980,8 +2981,11 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
if (refType.equals("contained") || refType.equals("bundled")) {
pol = ReferenceValidationPolicy.CHECK_VALID;
} else {
if (policyAdvisor == null) pol = ReferenceValidationPolicy.IGNORE;
else pol = policyAdvisor.policyForReference(this, hostContext.getAppContext(), path, ref);
if (policyAdvisor == null) {
pol = ReferenceValidationPolicy.IGNORE;
} else {
pol = policyAdvisor.policyForReference(this, hostContext.getAppContext(), path, ref);
}
}
if (pol.checkExists()) {
@ -4397,7 +4401,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
// this method is reentrant, but also the right place to tell the user what is going on if it's the root.
// if we're not at the root, we don't report progress
pctOwned = true;
pct = new PercentageTracker(resource.countDescendents()+1, resource.fhirType(), defn.getUrl());
pct = new PercentageTracker(resource.countDescendents()+1, resource.fhirType(), defn.getUrl(), logProgress);
}
if (BUNDLE.equals(element.fhirType())) {
if (debug) {
@ -4467,7 +4471,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
}
stack.resetIds();
if (pctOwned) {
pct = new PercentageTracker(resource.countDescendents(), resource.fhirType(), sd.getUrl());
pct = new PercentageTracker(resource.countDescendents(), resource.fhirType(), sd.getUrl(), logProgress);
}
startInner(hostContext, errors, resource, element, sd, stack, false, pct);
if (pctOwned) {
@ -4490,7 +4494,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
}
stack.resetIds();
if (pctOwned) {
pct = new PercentageTracker(resource.countDescendents(), resource.fhirType(), sd.getUrl());
pct = new PercentageTracker(resource.countDescendents(), resource.fhirType(), sd.getUrl(), logProgress);
}
startInner(hostContext, errors, resource, element, sd, stack, false, pct);
if (pctOwned) {
@ -6072,4 +6076,12 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
return this;
}
public boolean isLogProgress() {
return logProgress;
}
public void setLogProgress(boolean logProgress) {
this.logProgress = logProgress;
}
}

View File

@ -7,18 +7,30 @@ public class PercentageTracker {
private int total;
private int last;
private int current;
private boolean log;
private String url;
private static int instance;
public PercentageTracker(int total, String fhirType, String url) {
public PercentageTracker(int total, String fhirType, String url, boolean log) {
this.total = total;
instance++;
last = 0;
System.out.print("Validate "+fhirType+" against "+url);
this.log = log;
this.url = url;
if (log) {
System.out.print("Validate "+fhirType+" against "+url);
}
}
public void done() {
System.out.println("|");
if (log) {
System.out.println("|");
}
}
public String getUrl() {
return url;
}
public void seeElement(Element e) {
@ -28,10 +40,14 @@ public class PercentageTracker {
int pct = total == 0 ? 0: (current*100) / total;
if (pct > last + 2) {
while (last + 2 < pct) {
System.out.print(".");
if (log) {
System.out.print(".");
}
last = last + 2;
if (last % 20 == 0) {
System.out.print(""+last);
if (log) {
System.out.print(""+last);
}
}
}
}

View File

@ -132,7 +132,7 @@ public class ComparisonTests {
CanonicalResource left = load("left");
CanonicalResource right = load("right");
ComparisonSession session = new ComparisonSession(context, context, "Comparison Tests", null);
ComparisonSession session = new ComparisonSession(context, context, "Comparison Tests", null, null);
if (left instanceof CodeSystem && right instanceof CodeSystem) {
CodeSystemComparer cs = new CodeSystemComparer(session);

View File

@ -1292,3 +1292,43 @@ v: {
"system" : "http://loinc.org"
}
-------------------------------------------------------------------------------------
{"code" : {
"system" : "http://loinc.org",
"code" : "11502-2"
}, "url": "http://hl7.org/fhir/ValueSet/doc-typecodes--0", "version": "4.0.1", "lang":"null", "useServer":"true", "useClient":"false", "guessSystem":"false", "valueSetMode":"ALL_CHECKS", "versionFlexible":"false"}####
v: {
"display" : "Laboratory report",
"code" : "11502-2",
"system" : "http://loinc.org"
}
-------------------------------------------------------------------------------------
{"code" : {
"system" : "http://loinc.org",
"code" : "11502-2"
}, "url": "http://hl7.org/fhir/ValueSet/doc-typecodes", "version": "4.0.1", "lang":"null", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"NO_MEMBERSHIP_CHECK", "versionFlexible":"false"}####
v: {
"display" : "Laboratory report",
"code" : "11502-2",
"system" : "http://loinc.org"
}
-------------------------------------------------------------------------------------
{"code" : {
"system" : "http://loinc.org",
"code" : "11502-2"
}, "valueSet" :null, "lang":"null", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"ALL_CHECKS", "versionFlexible":"true"}####
v: {
"display" : "Laboratory report",
"code" : "11502-2",
"system" : "http://loinc.org"
}
-------------------------------------------------------------------------------------
{"code" : {
"system" : "http://loinc.org",
"code" : "11502-2"
}, "valueSet" :null, "lang":"null", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"ALL_CHECKS", "versionFlexible":"false"}####
v: {
"display" : "Laboratory report",
"code" : "11502-2",
"system" : "http://loinc.org"
}
-------------------------------------------------------------------------------------