fix bugs in FHIRPath checking and track special time when validating resources

This commit is contained in:
Grahame Grieve 2023-08-31 06:30:29 +02:00
parent 2deb88cdc9
commit 4bba1c2cde
7 changed files with 74 additions and 44 deletions

View File

@ -263,10 +263,7 @@ public class CanonicalResourceManager<T extends CanonicalResource> {
public void see(CachedCanonicalResource<T> cr) { public void see(CachedCanonicalResource<T> cr) {
// -- 1. exit conditions ----------------------------------------------------------------------------- // -- 1. exit conditions -----------------------------------------------------------------------------
if ("http://hl7.org/fhir/StructureDefinition/Address".equals(cr.getUrl())) {
System.out.println("!"); // #FIXME
}
// ignore UTG NUCC erroneous code system // ignore UTG NUCC erroneous code system
if (cr.getPackageInfo() != null if (cr.getPackageInfo() != null
&& cr.getPackageInfo().getId() != null && cr.getPackageInfo().getId() != null

View File

@ -444,7 +444,7 @@ public class FHIRPathEngine {
if (context == null) { if (context == null) {
types = null; // this is a special case; the first path reference will have to resolve to something in the context types = null; // this is a special case; the first path reference will have to resolve to something in the context
} else if (!context.contains(".")) { } else if (!context.contains(".")) {
StructureDefinition sd = worker.fetchTypeDefinition(resourceType); StructureDefinition sd = worker.fetchTypeDefinition(context);
if (sd == null) { if (sd == null) {
throw makeException(expr, I18nConstants.FHIRPATH_UNKNOWN_CONTEXT, context); throw makeException(expr, I18nConstants.FHIRPATH_UNKNOWN_CONTEXT, context);
} }

View File

@ -23,6 +23,7 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@ -65,6 +66,7 @@ import javax.annotation.Nullable;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.utilities.FileNotifier.FileNotifier2; import org.hl7.fhir.utilities.FileNotifier.FileNotifier2;
import org.hl7.fhir.utilities.Utilities.CaseInsensitiveSorter;
import org.hl7.fhir.utilities.settings.FhirSettings; import org.hl7.fhir.utilities.settings.FhirSettings;
public class Utilities { public class Utilities {
@ -1306,6 +1308,21 @@ public class Utilities {
return id.matches("[A-Za-z0-9\\-\\.]{1,64}"); return id.matches("[A-Za-z0-9\\-\\.]{1,64}");
} }
public static class CaseInsensitiveSorter implements Comparator<String> {
@Override
public int compare(String o1, String o2) {
return o1.compareToIgnoreCase(o2);
}
}
public static List<String> sortedCaseInsensitive(Collection<String> set) {
List<String> list = new ArrayList<>();
list.addAll(set);
Collections.sort(list, new CaseInsensitiveSorter());
return list;
}
public static List<String> sorted(Collection<String> set) { public static List<String> sorted(Collection<String> set) {
List<String> list = new ArrayList<>(); List<String> list = new ArrayList<>();
list.addAll(set); list.addAll(set);

View File

@ -6,6 +6,7 @@ public class TimeTracker {
private long sdTime = 0; private long sdTime = 0;
private long loadTime = 0; private long loadTime = 0;
private long fpeTime = 0; private long fpeTime = 0;
private long specTime = 0;
public long getOverall() { public long getOverall() {
return overall; return overall;
@ -22,6 +23,10 @@ public class TimeTracker {
public long getFpeTime() { public long getFpeTime() {
return fpeTime; return fpeTime;
} }
public long getSpecTime() {
return specTime;
}
public void load(long start) { public void load(long start) {
loadTime = loadTime + (System.nanoTime() - start); loadTime = loadTime + (System.nanoTime() - start);
@ -45,11 +50,16 @@ public class TimeTracker {
fpeTime = fpeTime + (System.nanoTime() - start); fpeTime = fpeTime + (System.nanoTime() - start);
} }
public void spec(long start) {
specTime = specTime + (System.nanoTime() - start);
}
public void reset() { public void reset() {
overall = 0; overall = 0;
txTime = 0; txTime = 0;
sdTime = 0; sdTime = 0;
loadTime = 0; loadTime = 0;
fpeTime = 0; fpeTime = 0;
specTime = 0;
} }
} }

View File

@ -5202,44 +5202,50 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
} }
public boolean checkSpecials(ValidatorHostContext hostContext, List<ValidationMessage> errors, Element element, NodeStack stack, boolean checkSpecials, PercentageTracker pct, ValidationMode mode) { public boolean checkSpecials(ValidatorHostContext hostContext, List<ValidationMessage> errors, Element element, NodeStack stack, boolean checkSpecials, PercentageTracker pct, ValidationMode mode) {
if (VersionUtilities.getCanonicalResourceNames(context.getVersion()).contains(element.getType())) {
Base base = element.getExtensionValue(ToolingExtensions.EXT_STANDARDS_STATUS); long t = System.nanoTime();
String standardsStatus = base != null && base.isPrimitive() ? base.primitiveValue() : null; try {
String status = element.getNamedChildValue("status"); if (VersionUtilities.getCanonicalResourceNames(context.getVersion()).contains(element.getType())) {
if (!Utilities.noString(status) && !Utilities.noString(standardsStatus)) { Base base = element.getExtensionValue(ToolingExtensions.EXT_STANDARDS_STATUS);
if (warning(errors, "2023-08-14", IssueType.BUSINESSRULE, element.line(), element.col(), stack.getLiteralPath(), statusCodesConsistent(status, standardsStatus), I18nConstants.VALIDATION_VAL_STATUS_INCONSISTENT, status, standardsStatus)) { String standardsStatus = base != null && base.isPrimitive() ? base.primitiveValue() : null;
hint(errors, "2023-08-14", IssueType.BUSINESSRULE, element.line(), element.col(), stack.getLiteralPath(), statusCodesDeeplyConsistent(status, standardsStatus), I18nConstants.VALIDATION_VAL_STATUS_INCONSISTENT_HINT, status, standardsStatus); String status = element.getNamedChildValue("status");
if (!Utilities.noString(status) && !Utilities.noString(standardsStatus)) {
if (warning(errors, "2023-08-14", IssueType.BUSINESSRULE, element.line(), element.col(), stack.getLiteralPath(), statusCodesConsistent(status, standardsStatus), I18nConstants.VALIDATION_VAL_STATUS_INCONSISTENT, status, standardsStatus)) {
hint(errors, "2023-08-14", IssueType.BUSINESSRULE, element.line(), element.col(), stack.getLiteralPath(), statusCodesDeeplyConsistent(status, standardsStatus), I18nConstants.VALIDATION_VAL_STATUS_INCONSISTENT_HINT, status, standardsStatus);
}
} }
} }
} if (element.getType().equals(BUNDLE)) {
if (element.getType().equals(BUNDLE)) { return new BundleValidator(this, serverBase).validateBundle(errors, element, stack, checkSpecials, hostContext, pct, mode);
return new BundleValidator(this, serverBase).validateBundle(errors, element, stack, checkSpecials, hostContext, pct, mode); } else if (element.getType().equals("Observation")) {
} else if (element.getType().equals("Observation")) { return validateObservation(errors, element, stack);
return validateObservation(errors, element, stack); } else if (element.getType().equals("Questionnaire")) {
} else if (element.getType().equals("Questionnaire")) { return new QuestionnaireValidator(this, myEnableWhenEvaluator, fpe, questionnaireMode).validateQuestionannaire(errors, element, element, stack);
return new QuestionnaireValidator(this, myEnableWhenEvaluator, fpe, questionnaireMode).validateQuestionannaire(errors, element, element, stack); } else if (element.getType().equals("QuestionnaireResponse")) {
} else if (element.getType().equals("QuestionnaireResponse")) { return new QuestionnaireValidator(this, myEnableWhenEvaluator, fpe, questionnaireMode).validateQuestionannaireResponse(hostContext, errors, element, stack);
return new QuestionnaireValidator(this, myEnableWhenEvaluator, fpe, questionnaireMode).validateQuestionannaireResponse(hostContext, errors, element, stack); } else if (element.getType().equals("Measure")) {
} else if (element.getType().equals("Measure")) { return new MeasureValidator(this).validateMeasure(hostContext, errors, element, stack);
return new MeasureValidator(this).validateMeasure(hostContext, errors, element, stack); } else if (element.getType().equals("MeasureReport")) {
} else if (element.getType().equals("MeasureReport")) { return new MeasureValidator(this).validateMeasureReport(hostContext, errors, element, stack);
return new MeasureValidator(this).validateMeasureReport(hostContext, errors, element, stack); } else if (element.getType().equals("CapabilityStatement")) {
} else if (element.getType().equals("CapabilityStatement")) { return validateCapabilityStatement(errors, element, stack);
return validateCapabilityStatement(errors, element, stack); } else if (element.getType().equals("CodeSystem")) {
} else if (element.getType().equals("CodeSystem")) { return new CodeSystemValidator(this).validateCodeSystem(errors, element, stack, baseOptions.withLanguage(stack.getWorkingLang()));
return new CodeSystemValidator(this).validateCodeSystem(errors, element, stack, baseOptions.withLanguage(stack.getWorkingLang())); } else if (element.getType().equals("ConceptMap")) {
} else if (element.getType().equals("ConceptMap")) { return new ConceptMapValidator(this).validateConceptMap(errors, element, stack, baseOptions.withLanguage(stack.getWorkingLang()));
return new ConceptMapValidator(this).validateConceptMap(errors, element, stack, baseOptions.withLanguage(stack.getWorkingLang())); } else if (element.getType().equals("SearchParameter")) {
} else if (element.getType().equals("SearchParameter")) { return new SearchParameterValidator(this, fpe).validateSearchParameter(errors, element, stack);
return new SearchParameterValidator(this, fpe).validateSearchParameter(errors, element, stack); } else if (element.getType().equals("StructureDefinition")) {
} else if (element.getType().equals("StructureDefinition")) { return new StructureDefinitionValidator(this, fpe, wantCheckSnapshotUnchanged).validateStructureDefinition(errors, element, stack);
return new StructureDefinitionValidator(this, fpe, wantCheckSnapshotUnchanged).validateStructureDefinition(errors, element, stack); } else if (element.getType().equals("StructureMap")) {
} else if (element.getType().equals("StructureMap")) { return new StructureMapValidator(this, fpe, profileUtilities).validateStructureMap(errors, element, stack);
return new StructureMapValidator(this, fpe, profileUtilities).validateStructureMap(errors, element, stack); } else if (element.getType().equals("ValueSet")) {
} else if (element.getType().equals("ValueSet")) { return new ValueSetValidator(this).validateValueSet(errors, element, stack);
return new ValueSetValidator(this).validateValueSet(errors, element, stack); } else {
} else { return true;
return true; }
} finally {
timeTracker.spec(t);
} }
} }
@ -6535,7 +6541,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
public String reportTimes() { public String reportTimes() {
String s = String.format("Times (ms): overall = %d, tx = %d, sd = %d, load = %d, fpe = %d", timeTracker.getOverall() / 1000000, timeTracker.getTxTime() / 1000000, timeTracker.getSdTime() / 1000000, timeTracker.getLoadTime() / 1000000, timeTracker.getFpeTime() / 1000000); String s = String.format("Times (ms): overall = %d, tx = %d, sd = %d, load = %d, fpe = %d, spec = %d", timeTracker.getOverall() / 1000000, timeTracker.getTxTime() / 1000000, timeTracker.getSdTime() / 1000000, timeTracker.getLoadTime() / 1000000, timeTracker.getFpeTime() / 1000000, timeTracker.getSpecTime() / 1000000);
timeTracker.reset(); timeTracker.reset();
return s; return s;
} }

View File

@ -536,7 +536,7 @@ public class StructureDefinitionValidator extends BaseValidator {
types.add(elements.get(0).getNamedChildValue("path")); types.add(elements.get(0).getNamedChildValue("path"));
} }
List<String> warnings = new ArrayList<>(); List<String> warnings = new ArrayList<>();
fpe.checkOnTypes(invariant, rootPath, types, fpe.parse(exp), warnings); fpe.checkOnTypes(invariant, "DomainResource", types, fpe.parse(exp), warnings);
for (String s : warnings) { for (String s : warnings) {
warning(errors, "2023-07-27", IssueType.BUSINESSRULE, stack, false, key+": "+s); warning(errors, "2023-07-27", IssueType.BUSINESSRULE, stack, false, key+": "+s);
} }

View File

@ -20,7 +20,7 @@
<properties> <properties>
<guava_version>32.0.1-jre</guava_version> <guava_version>32.0.1-jre</guava_version>
<hapi_fhir_version>6.4.1</hapi_fhir_version> <hapi_fhir_version>6.4.1</hapi_fhir_version>
<validator_test_case_version>1.4.1</validator_test_case_version> <validator_test_case_version>1.4.2-SNAPSHOT</validator_test_case_version>
<jackson_version>2.15.2</jackson_version> <jackson_version>2.15.2</jackson_version>
<junit_jupiter_version>5.9.2</junit_jupiter_version> <junit_jupiter_version>5.9.2</junit_jupiter_version>
<junit_platform_launcher_version>1.8.2</junit_platform_launcher_version> <junit_platform_launcher_version>1.8.2</junit_platform_launcher_version>