Refactor how observation profiles are registered in order to generalise management of extra profiles
This commit is contained in:
parent
04e95f4e05
commit
2f38cb544c
|
@ -0,0 +1,11 @@
|
||||||
|
package org.hl7.fhir.r5.utils.validation;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||||
|
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
|
||||||
|
|
||||||
|
public interface IMessagingServices {
|
||||||
|
ValidationMessage signpost(List<ValidationMessage> errors, String ruleDate, IssueType type, int line, int col, String path, String theMessage, Object... theMessageArguments);
|
||||||
|
|
||||||
|
}
|
|
@ -31,6 +31,7 @@ package org.hl7.fhir.r5.utils.validation;
|
||||||
|
|
||||||
|
|
||||||
import org.hl7.fhir.exceptions.FHIRException;
|
import org.hl7.fhir.exceptions.FHIRException;
|
||||||
|
import org.hl7.fhir.r5.context.IWorkerContext;
|
||||||
import org.hl7.fhir.r5.elementmodel.Manager.FhirFormat;
|
import org.hl7.fhir.r5.elementmodel.Manager.FhirFormat;
|
||||||
import org.hl7.fhir.r5.model.Coding;
|
import org.hl7.fhir.r5.model.Coding;
|
||||||
import org.hl7.fhir.r5.model.StructureDefinition;
|
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||||
|
@ -54,6 +55,8 @@ import java.util.List;
|
||||||
*/
|
*/
|
||||||
public interface IResourceValidator {
|
public interface IResourceValidator {
|
||||||
|
|
||||||
|
IWorkerContext getContext();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* how much to check displays for coded elements
|
* how much to check displays for coded elements
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -10,7 +10,6 @@ import org.hl7.fhir.r5.model.ValueSet;
|
||||||
import org.hl7.fhir.r5.utils.validation.constants.ContainedReferenceValidationPolicy;
|
import org.hl7.fhir.r5.utils.validation.constants.ContainedReferenceValidationPolicy;
|
||||||
import org.hl7.fhir.r5.utils.validation.constants.ReferenceValidationPolicy;
|
import org.hl7.fhir.r5.utils.validation.constants.ReferenceValidationPolicy;
|
||||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||||
import org.hl7.fhir.validation.instance.BasePolicyAdvisorForMandatoryProfiles;
|
|
||||||
import org.hl7.fhir.r5.utils.validation.constants.CodedContentValidationPolicy;
|
import org.hl7.fhir.r5.utils.validation.constants.CodedContentValidationPolicy;
|
||||||
import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor.ElementValidationAction;
|
import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor.ElementValidationAction;
|
||||||
import org.hl7.fhir.r5.utils.validation.constants.BindingKind;
|
import org.hl7.fhir.r5.utils.validation.constants.BindingKind;
|
||||||
|
@ -135,7 +134,7 @@ public interface IValidationPolicyAdvisor {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is called after a resource has been validated against the base structure,
|
* This is called after a resource has been validated against the base structure,
|
||||||
* but before any profiles specified in .meta.profile or in the parameters are applied.
|
* but before it's validated against any profiles specified in .meta.profile or in the parameters.
|
||||||
* This can be used to determine what additional profiles should be applied, for instance
|
* This can be used to determine what additional profiles should be applied, for instance
|
||||||
* those derived from the http://hl7.org/fhir/tools/StructureDefinition/profile-mapping extension
|
* those derived from the http://hl7.org/fhir/tools/StructureDefinition/profile-mapping extension
|
||||||
*
|
*
|
||||||
|
@ -144,9 +143,9 @@ public interface IValidationPolicyAdvisor {
|
||||||
* might be any version from R2-R6)
|
* might be any version from R2-R6)
|
||||||
*
|
*
|
||||||
* The base implementation applies the mandatory vital signs to observations that have LOINC or SNOMED CT
|
* The base implementation applies the mandatory vital signs to observations that have LOINC or SNOMED CT
|
||||||
* codes that indicate that they are vital signs. Note that these profiles are not optional; all resources
|
* codes that indicate that they are vital signs. Note that these profiles are not optional; all vital sign resources
|
||||||
* are required to conform to them. For this reason, if you're providing your own policy advisor, you should
|
* are required to conform to them. For this reason, if you're providing your own policy advisor, you should
|
||||||
* keep a reference to the default one, or call BasePolicyAdvisorForMandatoryProfiles. You can choose not to,
|
* keep a reference to the default one, or call BasePolicyAdvisorForFullValidation directly. You can choose not to,
|
||||||
* but if you do, you are allowing for resources that deviate from the FHIR specification (in a way that the
|
* but if you do, you are allowing for resources that deviate from the FHIR specification (in a way that the
|
||||||
* community considers clinically unsafe, since it means that software (probably) will miss vital signs for
|
* community considers clinically unsafe, since it means that software (probably) will miss vital signs for
|
||||||
* patients).
|
* patients).
|
||||||
|
@ -161,13 +160,14 @@ public interface IValidationPolicyAdvisor {
|
||||||
* @param messages all the validation messages. Implementations can inspect this, but the real purpose is to populate the messages with information messages explaining why profiles were (or weren't) applied
|
* @param messages all the validation messages. Implementations can inspect this, but the real purpose is to populate the messages with information messages explaining why profiles were (or weren't) applied
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
List<StructureDefinition> getImpliedProfilesForInstance(IResourceValidator validator,
|
List<StructureDefinition> getImpliedProfilesForResource(IResourceValidator validator,
|
||||||
Object appContext,
|
Object appContext,
|
||||||
String stackPath,
|
String stackPath,
|
||||||
ElementDefinition definition,
|
ElementDefinition definition,
|
||||||
StructureDefinition structure,
|
StructureDefinition structure,
|
||||||
Element resource,
|
Element resource,
|
||||||
boolean valid,
|
boolean valid,
|
||||||
|
IMessagingServices msgServices,
|
||||||
List<ValidationMessage> messages);
|
List<ValidationMessage> messages);
|
||||||
|
|
||||||
}
|
}
|
|
@ -67,6 +67,7 @@ import org.hl7.fhir.r5.terminologies.ValueSetUtilities;
|
||||||
import org.hl7.fhir.r5.utils.ToolingExtensions;
|
import org.hl7.fhir.r5.utils.ToolingExtensions;
|
||||||
import org.hl7.fhir.r5.utils.XVerExtensionManager;
|
import org.hl7.fhir.r5.utils.XVerExtensionManager;
|
||||||
import org.hl7.fhir.r5.utils.XVerExtensionManager.XVerExtensionStatus;
|
import org.hl7.fhir.r5.utils.XVerExtensionManager.XVerExtensionStatus;
|
||||||
|
import org.hl7.fhir.r5.utils.validation.IMessagingServices;
|
||||||
import org.hl7.fhir.r5.utils.validation.IResourceValidator;
|
import org.hl7.fhir.r5.utils.validation.IResourceValidator;
|
||||||
import org.hl7.fhir.r5.utils.validation.IValidatorResourceFetcher;
|
import org.hl7.fhir.r5.utils.validation.IValidatorResourceFetcher;
|
||||||
import org.hl7.fhir.r5.utils.validation.ValidationContextCarrier.IValidationContextResourceLoader;
|
import org.hl7.fhir.r5.utils.validation.ValidationContextCarrier.IValidationContextResourceLoader;
|
||||||
|
@ -87,7 +88,7 @@ import org.hl7.fhir.validation.cli.utils.ValidationLevel;
|
||||||
import org.hl7.fhir.validation.instance.utils.IndexedElement;
|
import org.hl7.fhir.validation.instance.utils.IndexedElement;
|
||||||
import org.hl7.fhir.validation.instance.utils.NodeStack;
|
import org.hl7.fhir.validation.instance.utils.NodeStack;
|
||||||
|
|
||||||
public class BaseValidator implements IValidationContextResourceLoader {
|
public class BaseValidator implements IValidationContextResourceLoader, IMessagingServices {
|
||||||
|
|
||||||
public static class BooleanHolder {
|
public static class BooleanHolder {
|
||||||
private boolean value = true;
|
private boolean value = true;
|
||||||
|
@ -411,7 +412,7 @@ public class BaseValidator implements IValidationContextResourceLoader {
|
||||||
return thePass;
|
return thePass;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ValidationMessage signpost(List<ValidationMessage> errors, String ruleDate, IssueType type, int line, int col, String path, String theMessage, Object... theMessageArguments) {
|
public ValidationMessage signpost(List<ValidationMessage> errors, String ruleDate, IssueType type, int line, int col, String path, String theMessage, Object... theMessageArguments) {
|
||||||
String message = context.formatMessage(theMessage, theMessageArguments);
|
String message = context.formatMessage(theMessage, theMessageArguments);
|
||||||
return addValidationMessage(errors, ruleDate, type, line, col, path, message, IssueSeverity.INFORMATION, theMessage).setSignpost(true);
|
return addValidationMessage(errors, ruleDate, type, line, col, path, message, IssueSeverity.INFORMATION, theMessage).setSignpost(true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,6 +67,7 @@ import org.hl7.fhir.r5.utils.EOperationOutcome;
|
||||||
import org.hl7.fhir.r5.utils.ToolingExtensions;
|
import org.hl7.fhir.r5.utils.ToolingExtensions;
|
||||||
import org.hl7.fhir.r5.utils.structuremap.StructureMapUtilities;
|
import org.hl7.fhir.r5.utils.structuremap.StructureMapUtilities;
|
||||||
import org.hl7.fhir.r5.utils.validation.BundleValidationRule;
|
import org.hl7.fhir.r5.utils.validation.BundleValidationRule;
|
||||||
|
import org.hl7.fhir.r5.utils.validation.IMessagingServices;
|
||||||
import org.hl7.fhir.r5.utils.validation.IResourceValidator;
|
import org.hl7.fhir.r5.utils.validation.IResourceValidator;
|
||||||
import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor;
|
import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor;
|
||||||
import org.hl7.fhir.r5.utils.validation.IValidatorResourceFetcher;
|
import org.hl7.fhir.r5.utils.validation.IValidatorResourceFetcher;
|
||||||
|
@ -104,6 +105,7 @@ import org.hl7.fhir.validation.cli.utils.ProfileLoader;
|
||||||
import org.hl7.fhir.validation.cli.utils.QuestionnaireMode;
|
import org.hl7.fhir.validation.cli.utils.QuestionnaireMode;
|
||||||
import org.hl7.fhir.validation.cli.utils.SchemaValidator;
|
import org.hl7.fhir.validation.cli.utils.SchemaValidator;
|
||||||
import org.hl7.fhir.validation.cli.utils.ValidationLevel;
|
import org.hl7.fhir.validation.cli.utils.ValidationLevel;
|
||||||
|
import org.hl7.fhir.validation.instance.BasePolicyAdvisorForFullValidation;
|
||||||
import org.hl7.fhir.validation.instance.InstanceValidator;
|
import org.hl7.fhir.validation.instance.InstanceValidator;
|
||||||
import org.hl7.fhir.validation.instance.utils.ValidationContext;
|
import org.hl7.fhir.validation.instance.utils.ValidationContext;
|
||||||
import org.hl7.fhir.utilities.ByteProvider;
|
import org.hl7.fhir.utilities.ByteProvider;
|
||||||
|
@ -1253,4 +1255,12 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<StructureDefinition> getImpliedProfilesForResource(IResourceValidator validator, Object appContext,
|
||||||
|
String stackPath, ElementDefinition definition, StructureDefinition structure, Element resource, boolean valid,
|
||||||
|
IMessagingServices msgServices, List<ValidationMessage> messages) {
|
||||||
|
return new BasePolicyAdvisorForFullValidation().getImpliedProfilesForResource(validator, appContext, stackPath,
|
||||||
|
definition, structure, resource, valid, msgServices, messages);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,11 +42,12 @@ import org.hl7.fhir.utilities.json.parser.JsonParser;
|
||||||
import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager;
|
import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager;
|
||||||
import org.hl7.fhir.utilities.npm.NpmPackage;
|
import org.hl7.fhir.utilities.npm.NpmPackage;
|
||||||
import org.hl7.fhir.validation.cli.utils.Common;
|
import org.hl7.fhir.validation.cli.utils.Common;
|
||||||
|
import org.hl7.fhir.validation.instance.BasePolicyAdvisorForFullValidation;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
|
||||||
public class StandAloneValidatorFetcher implements IValidatorResourceFetcher, IValidationPolicyAdvisor, IWorkerContextManager.ICanonicalResourceLocator {
|
public class StandAloneValidatorFetcher extends BasePolicyAdvisorForFullValidation implements IValidatorResourceFetcher, IValidationPolicyAdvisor, IWorkerContextManager.ICanonicalResourceLocator {
|
||||||
|
|
||||||
List<String> mappingsUris = new ArrayList<>();
|
List<String> mappingsUris = new ArrayList<>();
|
||||||
private FilesystemPackageCacheManager pcm;
|
private FilesystemPackageCacheManager pcm;
|
||||||
|
@ -76,31 +77,6 @@ public class StandAloneValidatorFetcher implements IValidatorResourceFetcher, IV
|
||||||
return ReferenceValidationPolicy.CHECK_TYPE_IF_EXISTS;
|
return ReferenceValidationPolicy.CHECK_TYPE_IF_EXISTS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public ContainedReferenceValidationPolicy policyForContained(IResourceValidator validator,
|
|
||||||
Object appContext,
|
|
||||||
StructureDefinition structure,
|
|
||||||
ElementDefinition element,
|
|
||||||
String containerType,
|
|
||||||
String containerId,
|
|
||||||
Element.SpecialElement containingResourceType,
|
|
||||||
String path,
|
|
||||||
String url) {
|
|
||||||
return ContainedReferenceValidationPolicy.CHECK_VALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public EnumSet<ResourceValidationAction> policyForResource(IResourceValidator validator, Object appContext,
|
|
||||||
StructureDefinition type, String path) {
|
|
||||||
return EnumSet.allOf(ResourceValidationAction.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public EnumSet<ElementValidationAction> policyForElement(IResourceValidator validator, Object appContext,
|
|
||||||
StructureDefinition structure, ElementDefinition element, String path) {
|
|
||||||
return EnumSet.allOf(ElementValidationAction.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean resolveURL(IResourceValidator validator, Object appContext, String path, String url, String type, boolean canonical) throws IOException, FHIRException {
|
public boolean resolveURL(IResourceValidator validator, Object appContext, String path, String url, String type, boolean canonical) throws IOException, FHIRException {
|
||||||
if (!Utilities.isAbsoluteUrl(url)) {
|
if (!Utilities.isAbsoluteUrl(url)) {
|
||||||
|
@ -316,19 +292,6 @@ public class StandAloneValidatorFetcher implements IValidatorResourceFetcher, IV
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public EnumSet<CodedContentValidationAction> policyForCodedContent(IResourceValidator validator,
|
|
||||||
Object appContext,
|
|
||||||
String stackPath,
|
|
||||||
ElementDefinition definition,
|
|
||||||
StructureDefinition structure,
|
|
||||||
BindingKind kind,
|
|
||||||
AdditionalBindingPurpose purpose,
|
|
||||||
ValueSet valueSet,
|
|
||||||
List<String> systems) {
|
|
||||||
return EnumSet.allOf(CodedContentValidationAction.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<String> fetchCanonicalResourceVersions(IResourceValidator validator, Object appContext, String url) {
|
public Set<String> fetchCanonicalResourceVersions(IResourceValidator validator, Object appContext, String url) {
|
||||||
return new HashSet<>();
|
return new HashSet<>();
|
||||||
|
|
|
@ -1,65 +1,166 @@
|
||||||
package org.hl7.fhir.validation.instance;
|
package org.hl7.fhir.validation.instance;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.hl7.fhir.r5.context.IWorkerContext;
|
||||||
import org.hl7.fhir.r5.elementmodel.Element;
|
import org.hl7.fhir.r5.elementmodel.Element;
|
||||||
import org.hl7.fhir.r5.elementmodel.Element.SpecialElement;
|
import org.hl7.fhir.r5.elementmodel.Element.SpecialElement;
|
||||||
import org.hl7.fhir.r5.model.ElementDefinition;
|
import org.hl7.fhir.r5.model.ElementDefinition;
|
||||||
import org.hl7.fhir.r5.model.StructureDefinition;
|
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||||
import org.hl7.fhir.r5.model.ValueSet;
|
import org.hl7.fhir.r5.model.ValueSet;
|
||||||
|
import org.hl7.fhir.r5.utils.validation.IMessagingServices;
|
||||||
import org.hl7.fhir.r5.utils.validation.IResourceValidator;
|
import org.hl7.fhir.r5.utils.validation.IResourceValidator;
|
||||||
import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor;
|
import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor;
|
||||||
|
import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor.AdditionalBindingPurpose;
|
||||||
|
import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor.CodedContentValidationAction;
|
||||||
|
import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor.ElementValidationAction;
|
||||||
|
import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor.ResourceValidationAction;
|
||||||
import org.hl7.fhir.r5.utils.validation.constants.BindingKind;
|
import org.hl7.fhir.r5.utils.validation.constants.BindingKind;
|
||||||
import org.hl7.fhir.r5.utils.validation.constants.ContainedReferenceValidationPolicy;
|
import org.hl7.fhir.r5.utils.validation.constants.ContainedReferenceValidationPolicy;
|
||||||
import org.hl7.fhir.r5.utils.validation.constants.ReferenceValidationPolicy;
|
import org.hl7.fhir.r5.utils.validation.constants.ReferenceValidationPolicy;
|
||||||
|
import org.hl7.fhir.utilities.Utilities;
|
||||||
|
import org.hl7.fhir.utilities.VersionUtilities;
|
||||||
|
import org.hl7.fhir.utilities.i18n.I18nConstants;
|
||||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||||
|
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
|
||||||
|
|
||||||
public class BasePolicyAdvisorForFullValidation implements IValidationPolicyAdvisor {
|
public class BasePolicyAdvisorForFullValidation implements IValidationPolicyAdvisor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ReferenceValidationPolicy policyForReference(IResourceValidator validator, Object appContext, String path,
|
public ReferenceValidationPolicy policyForReference(IResourceValidator validator, Object appContext, String path, String url) {
|
||||||
String url) {
|
return ReferenceValidationPolicy.CHECK_TYPE_IF_EXISTS;
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ContainedReferenceValidationPolicy policyForContained(IResourceValidator validator, Object appContext,
|
public ContainedReferenceValidationPolicy policyForContained(IResourceValidator validator, Object appContext,
|
||||||
StructureDefinition structure, ElementDefinition element, String containerType, String containerId,
|
StructureDefinition structure, ElementDefinition element, String containerType, String containerId,
|
||||||
SpecialElement containingResourceType, String path, String url) {
|
SpecialElement containingResourceType, String path, String url) {
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return null;
|
return ContainedReferenceValidationPolicy.CHECK_VALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EnumSet<ResourceValidationAction> policyForResource(IResourceValidator validator, Object appContext,
|
public EnumSet<ResourceValidationAction> policyForResource(IResourceValidator validator, Object appContext,
|
||||||
StructureDefinition type, String path) {
|
StructureDefinition type, String path) {
|
||||||
// TODO Auto-generated method stub
|
return EnumSet.allOf(ResourceValidationAction.class);
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EnumSet<ElementValidationAction> policyForElement(IResourceValidator validator, Object appContext,
|
public EnumSet<ElementValidationAction> policyForElement(IResourceValidator validator, Object appContext,
|
||||||
StructureDefinition structure, ElementDefinition element, String path) {
|
StructureDefinition structure, ElementDefinition element, String path) {
|
||||||
// TODO Auto-generated method stub
|
return EnumSet.allOf(ElementValidationAction.class);
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EnumSet<CodedContentValidationAction> policyForCodedContent(IResourceValidator validator, Object appContext,
|
public EnumSet<CodedContentValidationAction> policyForCodedContent(IResourceValidator validator,
|
||||||
String stackPath, ElementDefinition definition, StructureDefinition structure, BindingKind kind,
|
Object appContext,
|
||||||
AdditionalBindingPurpose purpose, ValueSet valueSet, List<String> systems) {
|
String stackPath,
|
||||||
// TODO Auto-generated method stub
|
ElementDefinition definition,
|
||||||
return null;
|
StructureDefinition structure,
|
||||||
|
BindingKind kind,
|
||||||
|
AdditionalBindingPurpose purpose,
|
||||||
|
ValueSet valueSet,
|
||||||
|
List<String> systems) {
|
||||||
|
return EnumSet.allOf(CodedContentValidationAction.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<StructureDefinition> getImpliedProfilesForInstance(IResourceValidator validator, Object appContext,
|
public List<StructureDefinition> getImpliedProfilesForResource(IResourceValidator validator, Object appContext,
|
||||||
String stackPath, ElementDefinition definition, StructureDefinition structure, Element resource, boolean valid,
|
String stackPath, ElementDefinition definition, StructureDefinition structure, Element resource, boolean valid,
|
||||||
List<ValidationMessage> messages) {
|
IMessagingServices msgServices, List<ValidationMessage> messages) {
|
||||||
// TODO Auto-generated method stub
|
List<StructureDefinition> profiles = new ArrayList<StructureDefinition>();
|
||||||
return null;
|
if ("Observation".equals(resource.fhirType()) && VersionUtilities.isR4Plus(validator.getContext().getVersion())) {
|
||||||
|
getImpliedProfilesForObservation(profiles, msgServices, messages, validator.getContext(), stackPath, resource);
|
||||||
|
}
|
||||||
|
return profiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void getImpliedProfilesForObservation(List<StructureDefinition> profiles, IMessagingServices msgServices, List<ValidationMessage> messages, IWorkerContext context, String stackPath, Element resource) {
|
||||||
|
Element code = resource.getNamedChild("code", false);
|
||||||
|
List<String> codes = new ArrayList<>();
|
||||||
|
if (hasLoincCode(code, codes, "85353-1")) {
|
||||||
|
addProfile(profiles, msgServices, messages, context, stackPath, resource, "http://hl7.org/fhir/StructureDefinition/vitalspanel", "Vital Signs Panel", "LOINC", codes);
|
||||||
|
} else if (hasLoincCode(code, codes, "9279-1", "76170-0", "76172-6", "76171-8", "19840-8", "33438-3", "76270-8", "11291-2")) {
|
||||||
|
addProfile(profiles, msgServices, messages, context, stackPath, resource, "http://hl7.org/fhir/StructureDefinition/resprate", "Respiratory Rate", "LOINC", codes);
|
||||||
|
} else if (hasLoincCode(code, codes, "60978-4", "73795-7", "73799-9", "76476-1", "76477-9", "8867-4", "8889-8", "8890-6", "8891-4", "8892-2", "8893-0", "40443-4", "55425-3", "68999-2", "11328-2", "69000-8", "69000-8", "60978-4", "60978-4", "8890-6", "8886-4", "68999-2", "68999-2")) {
|
||||||
|
addProfile(profiles, msgServices, messages, context, stackPath, resource, "http://hl7.org/fhir/StructureDefinition/heartrate", "Heart rate", "LOINC", codes);
|
||||||
|
} else if (hasLoincCode(code, codes, "2708-6", "19224-5", "20564-1", "2709-4", "2710-2", "2713-6", "51733-4", "59408-5", "59417-6", "89276-0", "97549-0")) {
|
||||||
|
addProfile(profiles, msgServices, messages, context, stackPath, resource, "http://hl7.org/fhir/StructureDefinition/oxygensat", "Oxygen saturation", "LOINC", codes);
|
||||||
|
} else if (hasLoincCode(code, codes, "8310-5", "60834-9", "60835-6", "60836-4", "60838-0", "60955-2", "61009-7", "75539-7", "75987-8", "76010-8", "76011-6", "76278-1", "8309-7", "8310-5", "8328-7", "8329-5", "8330-3", "8331-1", "8332-9", "8333-7", "8334-5", "91371-5", "98657-0", "98663-8")) {
|
||||||
|
addProfile(profiles, msgServices, messages, context, stackPath, resource, "http://hl7.org/fhir/StructureDefinition/bodytemp", "Body temperature", "LOINC", codes);
|
||||||
|
} else if (hasLoincCode(code, codes, "8302-2", "3137-7", "3138-5", "8302-2", "8306-3", "8308-9")) {
|
||||||
|
addProfile(profiles, msgServices, messages, context, stackPath, resource, "http://hl7.org/fhir/StructureDefinition/bodyheight", "Body height", "LOINC", codes);
|
||||||
|
} else if (hasLoincCode(code, codes, "9843-4", "8287-5", "9843-4")) {
|
||||||
|
addProfile(profiles, msgServices, messages, context, stackPath, resource, "http://hl7.org/fhir/StructureDefinition/headcircum", "Head circumference", "LOINC", codes);
|
||||||
|
} else if (hasLoincCode(code, codes, "29463-7", "29463-7", "3141-9", "3142-7", "75292-3", "79348-9", "8350-1", "8351-9")) {
|
||||||
|
addProfile(profiles, msgServices, messages, context, stackPath, resource, "http://hl7.org/fhir/StructureDefinition/bodyweight", "Body weight", "LOINC", codes);
|
||||||
|
} else if (hasLoincCode(code, codes, "39156-5", "39156-5", "59574-4", "89270-3")) {
|
||||||
|
addProfile(profiles, msgServices, messages, context, stackPath, resource, "http://hl7.org/fhir/StructureDefinition/bmi", "Body mass index", "LOINC", codes);
|
||||||
|
} else if (hasLoincCode(code, codes, "85354-9", "35094-2", "8459-0", "85354-9", "76534-7", "55284-4", "8480-6")) {
|
||||||
|
addProfile(profiles, msgServices, messages, context, stackPath, resource, "http://hl7.org/fhir/StructureDefinition/bp", "Blood pressure systolic and diastolic", "LOINC", codes);
|
||||||
|
|
||||||
|
} else if (hasSctCode(code, codes, "46680005")) {
|
||||||
|
addProfile(profiles, msgServices, messages, context, stackPath, resource, "http://hl7.org/fhir/StructureDefinition/vitalspanel", "Vital Signs Panel", "SNOMED CT", codes);
|
||||||
|
} else if (hasSctCode(code, codes, "86290005", "271625008", "271306003")) {
|
||||||
|
addProfile(profiles, msgServices, messages, context, stackPath, resource, "http://hl7.org/fhir/StructureDefinition/bp", "Blood pressure systolic and diastolic", "SNOMED CT", codes);
|
||||||
|
} else if (hasSctCode(code, codes, "271306003", "249043002", "444981005", "399017001", "251670001", "429525003", "429614003")) {
|
||||||
|
addProfile(profiles, msgServices, messages, context, stackPath, resource, "http://hl7.org/fhir/StructureDefinition/heartrate", "Heart rate", "SNOMED CT", codes);
|
||||||
|
} else if (hasSctCode(code, codes, "103228002", "103228002", "442349007", "442476006", "442440005", "431314004", "442734002", "713194001")) {
|
||||||
|
addProfile(profiles, msgServices, messages, context, stackPath, resource, "http://hl7.org/fhir/StructureDefinition/oxygensat", "Oxygen saturation", "SNOMED CT", codes);
|
||||||
|
} else if (hasSctCode(code, codes, "386725007", "276885007", "300076005", "1222808002", "364246006", "307047009", "708499008", "708499008", "431598003", "698831002", "698832009", "415882003", "415974002", "415929009", "415945006")) {
|
||||||
|
addProfile(profiles, msgServices, messages, context, stackPath, resource, "http://hl7.org/fhir/StructureDefinition/bodytemp", "Body temperature", "SNOMED CT", codes);
|
||||||
|
} else if (hasSctCode(code, codes, "1153637007", "1162419008", "50373000", "1162418000", "1230278008", "1162392001", "1162417005")) {
|
||||||
|
addProfile(profiles, msgServices, messages, context, stackPath, resource, "http://hl7.org/fhir/StructureDefinition/bodyheight", "Body height", "SNOMED CT", codes);
|
||||||
|
} else if (hasSctCode(code, codes, "363812007", "169876006", "1269262007", "363811000")) {
|
||||||
|
addProfile(profiles, msgServices, messages, context, stackPath, resource, "http://hl7.org/fhir/StructureDefinition/headcircum", "Head circumference", "SNOMED CT", codes);
|
||||||
|
} else if (hasSctCode(code, codes, "363811000", "60621009", "735395000", "425024002", "424927000", "784399000", "1162416001", "1162415002")) {
|
||||||
|
addProfile(profiles, msgServices, messages, context, stackPath, resource, "http://hl7.org/fhir/StructureDefinition/bodyweight", "Body weight", "SNOMED CT", codes);
|
||||||
|
} else if (hasSctCode(code, codes, "60621009")) {
|
||||||
|
addProfile(profiles, msgServices, messages, context, stackPath, resource, "http://hl7.org/fhir/StructureDefinition/bmi", "Body mass index", "SNOMED CT", codes);
|
||||||
|
} else if (hasSctCode(code, codes, "75367002", "251076008", "163033001", "163035008", "386534000", "386536003", "271649006", "271649006", "271650006", "407556006", "407554009", "716579001", "399304008")) {
|
||||||
|
addProfile(profiles, msgServices, messages, context, stackPath, resource, "http://hl7.org/fhir/StructureDefinition/bp", "Blood pressure systolic and diastolic", "SNOMED CT", codes);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addProfile(List<StructureDefinition> profiles, IMessagingServices msgServices, List<ValidationMessage> messages, IWorkerContext context, String stackPath, Element resource, String url, String name, String systemName, List<String> codes) {
|
||||||
|
resource.addMessage(msgServices.signpost(messages, null, IssueType.INFORMATIONAL, resource.line(), resource.col(), stackPath, I18nConstants.VALIDATION_VAL_PROFILE_SIGNPOST_OBS, url, name, systemName, codes.get(0)));
|
||||||
|
StructureDefinition sd = context.fetchResource(StructureDefinition.class, url);
|
||||||
|
if (sd != null) {
|
||||||
|
profiles.add(sd);
|
||||||
|
} else {
|
||||||
|
// complain?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean hasLoincCode(Element code, List<String> codes, String... values) {
|
||||||
|
if (code != null) {
|
||||||
|
List<Element> codings = code.getChildren("coding");
|
||||||
|
for (Element coding : codings) {
|
||||||
|
if ("http://loinc.org".equals(coding.getNamedChildValue("system", false)) && Utilities.existsInList(coding.getNamedChildValue("code", false), values)) {
|
||||||
|
codes.add(coding.getNamedChildValue("code", false));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean hasSctCode(Element code, List<String> codes, String... values) {
|
||||||
|
if (code != null) {
|
||||||
|
List<Element> codings = code.getChildren("coding");
|
||||||
|
for (Element coding : codings) {
|
||||||
|
if ("http://snomed.info/sct".equals(coding.getNamedChildValue("system", false)) && Utilities.existsInList(coding.getNamedChildValue("code", false), values)) {
|
||||||
|
codes.add(coding.getNamedChildValue("code", false));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -173,6 +173,7 @@ import org.hl7.fhir.r5.utils.XVerExtensionManager;
|
||||||
import org.hl7.fhir.r5.utils.XVerExtensionManager.XVerExtensionStatus;
|
import org.hl7.fhir.r5.utils.XVerExtensionManager.XVerExtensionStatus;
|
||||||
import org.hl7.fhir.r5.utils.sql.Validator;
|
import org.hl7.fhir.r5.utils.sql.Validator;
|
||||||
import org.hl7.fhir.r5.utils.validation.BundleValidationRule;
|
import org.hl7.fhir.r5.utils.validation.BundleValidationRule;
|
||||||
|
import org.hl7.fhir.r5.utils.validation.IMessagingServices;
|
||||||
import org.hl7.fhir.r5.utils.validation.IResourceValidator;
|
import org.hl7.fhir.r5.utils.validation.IResourceValidator;
|
||||||
import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor;
|
import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor;
|
||||||
import org.hl7.fhir.r5.utils.validation.IValidationProfileUsageTracker;
|
import org.hl7.fhir.r5.utils.validation.IValidationProfileUsageTracker;
|
||||||
|
@ -595,7 +596,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
private boolean noBindingMsgSuppressed;
|
private boolean noBindingMsgSuppressed;
|
||||||
private Map<String, Element> fetchCache = new HashMap<>();
|
private Map<String, Element> fetchCache = new HashMap<>();
|
||||||
private HashMap<Element, ResourceValidationTracker> resourceTracker = new HashMap<>();
|
private HashMap<Element, ResourceValidationTracker> resourceTracker = new HashMap<>();
|
||||||
private IValidationPolicyAdvisor policyAdvisor;
|
private IValidationPolicyAdvisor policyAdvisor = new BasePolicyAdvisorForFullValidation();
|
||||||
long time = 0;
|
long time = 0;
|
||||||
long start = 0;
|
long start = 0;
|
||||||
long lastlog = 0;
|
long lastlog = 0;
|
||||||
|
@ -691,6 +692,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IResourceValidator setPolicyAdvisor(IValidationPolicyAdvisor advisor) {
|
public IResourceValidator setPolicyAdvisor(IValidationPolicyAdvisor advisor) {
|
||||||
|
if (advisor == null) {
|
||||||
|
throw new Error("Cannot set advisor to null");
|
||||||
|
}
|
||||||
this.policyAdvisor = advisor;
|
this.policyAdvisor = advisor;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -3111,7 +3115,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
}
|
}
|
||||||
if (!found) {
|
if (!found) {
|
||||||
if (type.equals("canonical")) {
|
if (type.equals("canonical")) {
|
||||||
ReferenceValidationPolicy rp = policyAdvisor == null ? ReferenceValidationPolicy.CHECK_VALID : policyAdvisor.policyForReference(this, valContext, path, url);
|
ReferenceValidationPolicy rp = policyAdvisor.policyForReference(this, valContext, path, url);
|
||||||
if (rp == ReferenceValidationPolicy.CHECK_EXISTS || rp == ReferenceValidationPolicy.CHECK_EXISTS_AND_TYPE) {
|
if (rp == ReferenceValidationPolicy.CHECK_EXISTS || rp == ReferenceValidationPolicy.CHECK_EXISTS_AND_TYPE) {
|
||||||
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, false, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_CANONICAL_RESOLVE, url) && ok;
|
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, false, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_CANONICAL_RESOLVE, url) && ok;
|
||||||
} else {
|
} else {
|
||||||
|
@ -3128,7 +3132,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (type.equals("canonical")) {
|
if (type.equals("canonical")) {
|
||||||
ReferenceValidationPolicy rp = policyAdvisor == null ? ReferenceValidationPolicy.CHECK_VALID : policyAdvisor.policyForReference(this, valContext, path, url);
|
ReferenceValidationPolicy rp = policyAdvisor.policyForReference(this, valContext, path, url);
|
||||||
if (rp == ReferenceValidationPolicy.CHECK_EXISTS_AND_TYPE || rp == ReferenceValidationPolicy.CHECK_TYPE_IF_EXISTS || rp == ReferenceValidationPolicy.CHECK_VALID) {
|
if (rp == ReferenceValidationPolicy.CHECK_EXISTS_AND_TYPE || rp == ReferenceValidationPolicy.CHECK_TYPE_IF_EXISTS || rp == ReferenceValidationPolicy.CHECK_VALID) {
|
||||||
try {
|
try {
|
||||||
Resource r = null;
|
Resource r = null;
|
||||||
|
@ -3581,8 +3585,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
ok = false;
|
ok = false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
EnumSet<CodedContentValidationAction> validationPolicy = getPolicyAdvisor() == null ?
|
EnumSet<CodedContentValidationAction> validationPolicy = policyAdvisor.policyForCodedContent(this, valContext, stack.getLiteralPath(), elementContext, profile, BindingKind.PRIMARY, null, vs, new ArrayList<>());
|
||||||
EnumSet.allOf(CodedContentValidationAction.class) : getPolicyAdvisor().policyForCodedContent(this, valContext, stack.getLiteralPath(), elementContext, profile, BindingKind.PRIMARY, null, vs, new ArrayList<>());
|
|
||||||
|
|
||||||
if (!validationPolicy.isEmpty()) {
|
if (!validationPolicy.isEmpty()) {
|
||||||
long t = System.nanoTime();
|
long t = System.nanoTime();
|
||||||
|
@ -3918,11 +3921,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
if (refType.equals("contained") || refType.equals("bundled")) {
|
if (refType.equals("contained") || refType.equals("bundled")) {
|
||||||
pol = ReferenceValidationPolicy.CHECK_VALID;
|
pol = ReferenceValidationPolicy.CHECK_VALID;
|
||||||
} else {
|
} else {
|
||||||
if (policyAdvisor == null) {
|
pol = policyAdvisor.policyForReference(this, valContext.getAppContext(), path, ref);
|
||||||
pol = ReferenceValidationPolicy.IGNORE;
|
|
||||||
} else {
|
|
||||||
pol = policyAdvisor.policyForReference(this, valContext.getAppContext(), path, ref);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conditional) {
|
if (conditional) {
|
||||||
|
@ -5705,15 +5704,22 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
ok = false;
|
ok = false;
|
||||||
}
|
}
|
||||||
if (checkSpecials) {
|
if (checkSpecials) {
|
||||||
ok = checkSpecials(valContext, errors, element, stack, checkSpecials, pct, mode, fromContained) && ok;
|
ok = checkSpecials(valContext, errors, element, stack, checkSpecials, pct, mode, fromContained, ok) && ok;
|
||||||
ok = validateResourceRules(errors, element, stack) && ok;
|
ok = validateResourceRules(errors, element, stack) && ok;
|
||||||
}
|
}
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean checkSpecials(ValidationContext valContext, List<ValidationMessage> errors, Element element, NodeStack stack, boolean checkSpecials, PercentageTracker pct, ValidationMode mode, boolean contained) {
|
public boolean checkSpecials(ValidationContext valContext, List<ValidationMessage> errors, Element element, NodeStack stack, boolean checkSpecials, PercentageTracker pct, ValidationMode mode, boolean contained, boolean isOk) {
|
||||||
boolean ok = true;
|
boolean ok = true;
|
||||||
|
|
||||||
|
// first, does the policy advisor have profiles it wants us to check?
|
||||||
|
List<StructureDefinition> profiles = policyAdvisor.getImpliedProfilesForResource(this, valContext.getAppContext(), stack.getLiteralPath(),
|
||||||
|
element.getProperty().getDefinition(), element.getProperty().getStructure(), element, isOk, this, errors);
|
||||||
|
for (StructureDefinition sd : profiles) {
|
||||||
|
ok = startInner(valContext, errors, element, element, sd, stack, false, pct, mode, false) && ok;
|
||||||
|
}
|
||||||
|
|
||||||
long t = System.nanoTime();
|
long t = System.nanoTime();
|
||||||
try {
|
try {
|
||||||
if (VersionUtilities.getCanonicalResourceNames(context.getVersion()).contains(element.getType())) {
|
if (VersionUtilities.getCanonicalResourceNames(context.getVersion()).contains(element.getType())) {
|
||||||
|
@ -5966,8 +5972,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
} else {
|
} else {
|
||||||
SpecialElement special = element.getSpecial();
|
SpecialElement special = element.getSpecial();
|
||||||
|
|
||||||
ContainedReferenceValidationPolicy containedValidationPolicy = getPolicyAdvisor() == null ?
|
ContainedReferenceValidationPolicy containedValidationPolicy = policyAdvisor.policyForContained(this,
|
||||||
ContainedReferenceValidationPolicy.CHECK_VALID : getPolicyAdvisor().policyForContained(this,
|
|
||||||
valContext, parentProfile, child, context.fhirType(), context.getId(), special, path, parentProfile.getUrl());
|
valContext, parentProfile, child, context.fhirType(), context.getId(), special, path, parentProfile.getUrl());
|
||||||
|
|
||||||
if (containedValidationPolicy.ignore()) {
|
if (containedValidationPolicy.ignore()) {
|
||||||
|
@ -6021,7 +6026,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
checkSpecials(valContext, errors, element, stack, ok, pct, mode, true);
|
checkSpecials(valContext, errors, element, stack, ok, pct, mode, true, ok);
|
||||||
|
|
||||||
if (typeForResource.getProfile().size() == 1) {
|
if (typeForResource.getProfile().size() == 1) {
|
||||||
long t = System.nanoTime();
|
long t = System.nanoTime();
|
||||||
|
@ -6427,8 +6432,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
if (debug) {
|
if (debug) {
|
||||||
System.out.println(" check " + localStack.getLiteralPath()+" against "+ei.getDefinition().getId()+" in profile "+profile.getVersionedUrl()+time());
|
System.out.println(" check " + localStack.getLiteralPath()+" against "+ei.getDefinition().getId()+" in profile "+profile.getVersionedUrl()+time());
|
||||||
}
|
}
|
||||||
EnumSet<ElementValidationAction> actionSet = policyAdvisor == null ? EnumSet.allOf(ElementValidationAction.class) :
|
EnumSet<ElementValidationAction> actionSet = policyAdvisor.policyForElement(this, valContext.getAppContext(), profile, ei.getDefinition(), localStack.getLiteralPath());
|
||||||
policyAdvisor.policyForElement(this, valContext.getAppContext(), profile, ei.getDefinition(), localStack.getLiteralPath());
|
|
||||||
|
|
||||||
String localStackLiteralPath = localStack.getLiteralPath();
|
String localStackLiteralPath = localStack.getLiteralPath();
|
||||||
String eiPath = ei.getPath();
|
String eiPath = ei.getPath();
|
||||||
|
|
|
@ -181,7 +181,7 @@ public class BundleValidator extends BaseValidator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// also, while we're here, check the specials, since this doesn't happen anywhere else
|
// also, while we're here, check the specials, since this doesn't happen anywhere else
|
||||||
((InstanceValidator) parent).checkSpecials(hostContext, errors, res, rstack, true, pct, mode, true);
|
((InstanceValidator) parent).checkSpecials(hostContext, errors, res, rstack, true, pct, mode, true, ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: check specials
|
// todo: check specials
|
||||||
|
|
|
@ -38,92 +38,8 @@ public class ObservationValidator extends BaseValidator {
|
||||||
element.getNamedChild("effectiveTiming", false) != null || element.getNamedChild("effectiveInstant", false) != null,
|
element.getNamedChild("effectiveTiming", false) != null || element.getNamedChild("effectiveInstant", false) != null,
|
||||||
I18nConstants.ALL_OBSERVATIONS_SHOULD_HAVE_AN_EFFECTIVEDATETIME_OR_AN_EFFECTIVEPERIOD, element.getProperty().typeSummary()) && ok;
|
I18nConstants.ALL_OBSERVATIONS_SHOULD_HAVE_AN_EFFECTIVEDATETIME_OR_AN_EFFECTIVEPERIOD, element.getProperty().typeSummary()) && ok;
|
||||||
|
|
||||||
// hook in the vital signs
|
// Looking for the vital signs code? It's moved to BasePolicyAdvisorForFullValidation.getImpliedProfilesForObservation
|
||||||
if (VersionUtilities.isR4Plus(context.getVersion())) {
|
|
||||||
Element code = element.getNamedChild("code", false);
|
|
||||||
List<String> codes = new ArrayList<>();
|
|
||||||
if (hasLoincCode(code, codes, "85353-1")) {
|
|
||||||
ok = checkObservationAgainstProfile(valContext, errors, element, stack, "http://hl7.org/fhir/StructureDefinition/vitalspanel", "Vital Signs Panel", "LOINC", codes, pct, mode) && ok;
|
|
||||||
} else if (hasLoincCode(code, codes, "9279-1", "76170-0", "76172-6", "76171-8", "19840-8", "33438-3", "76270-8", "11291-2")) {
|
|
||||||
ok = checkObservationAgainstProfile(valContext,errors, element, stack, "http://hl7.org/fhir/StructureDefinition/resprate", "Respiratory Rate", "LOINC", codes, pct, mode) && ok;
|
|
||||||
} else if (hasLoincCode(code, codes, "60978-4", "73795-7", "73799-9", "76476-1", "76477-9", "8867-4", "8889-8", "8890-6", "8891-4", "8892-2", "8893-0", "40443-4", "55425-3", "68999-2", "11328-2", "69000-8", "69000-8", "60978-4", "60978-4", "8890-6", "8886-4", "68999-2", "68999-2")) {
|
|
||||||
ok = checkObservationAgainstProfile(valContext,errors, element, stack, "http://hl7.org/fhir/StructureDefinition/heartrate", "Heart rate", "LOINC", codes, pct, mode) && ok;
|
|
||||||
} else if (hasLoincCode(code, codes, "2708-6", "19224-5", "20564-1", "2709-4", "2710-2", "2713-6", "51733-4", "59408-5", "59417-6", "89276-0", "97549-0")) {
|
|
||||||
ok = checkObservationAgainstProfile(valContext,errors, element, stack, "http://hl7.org/fhir/StructureDefinition/oxygensat", "Oxygen saturation", "LOINC", codes, pct, mode) && ok;
|
|
||||||
} else if (hasLoincCode(code, codes, "8310-5", "60834-9", "60835-6", "60836-4", "60838-0", "60955-2", "61009-7", "75539-7", "75987-8", "76010-8", "76011-6", "76278-1", "8309-7", "8310-5", "8328-7", "8329-5", "8330-3", "8331-1", "8332-9", "8333-7", "8334-5", "91371-5", "98657-0", "98663-8")) {
|
|
||||||
ok = checkObservationAgainstProfile(valContext,errors, element, stack, "http://hl7.org/fhir/StructureDefinition/bodytemp", "Body temperature", "LOINC", codes, pct, mode) && ok;
|
|
||||||
} else if (hasLoincCode(code, codes, "8302-2", "3137-7", "3138-5", "8302-2", "8306-3", "8308-9")) {
|
|
||||||
ok = checkObservationAgainstProfile(valContext,errors, element, stack, "http://hl7.org/fhir/StructureDefinition/bodyheight", "Body height", "LOINC", codes, pct, mode) && ok;
|
|
||||||
} else if (hasLoincCode(code, codes, "9843-4", "8287-5", "9843-4")) {
|
|
||||||
ok = checkObservationAgainstProfile(valContext,errors, element, stack, "http://hl7.org/fhir/StructureDefinition/headcircum", "Head circumference", "LOINC", codes, pct, mode) && ok;
|
|
||||||
} else if (hasLoincCode(code, codes, "29463-7", "29463-7", "3141-9", "3142-7", "75292-3", "79348-9", "8350-1", "8351-9")) {
|
|
||||||
ok = checkObservationAgainstProfile(valContext,errors, element, stack, "http://hl7.org/fhir/StructureDefinition/bodyweight", "Body weight", "LOINC", codes, pct, mode) && ok;
|
|
||||||
} else if (hasLoincCode(code, codes, "39156-5", "39156-5", "59574-4", "89270-3")) {
|
|
||||||
ok = checkObservationAgainstProfile(valContext,errors, element, stack, "http://hl7.org/fhir/StructureDefinition/bmi", "Body mass index", "LOINC", codes, pct, mode) && ok;
|
|
||||||
} else if (hasLoincCode(code, codes, "85354-9", "35094-2", "8459-0", "85354-9", "76534-7", "55284-4", "8480-6")) {
|
|
||||||
ok = checkObservationAgainstProfile(valContext,errors, element, stack, "http://hl7.org/fhir/StructureDefinition/bp", "Blood pressure systolic and diastolic", "LOINC", codes, pct, mode) && ok;
|
|
||||||
|
|
||||||
} else if (hasSctCode(code, codes, "46680005")) {
|
|
||||||
ok = checkObservationAgainstProfile(valContext, errors, element, stack, "http://hl7.org/fhir/StructureDefinition/vitalspanel", "Vital Signs Panel", "SNOMED CT", codes, pct, mode) && ok;
|
|
||||||
} else if (hasSctCode(code, codes, "86290005", "271625008", "271306003")) {
|
|
||||||
ok = checkObservationAgainstProfile(valContext,errors, element, stack, "Blood pressure systolic and diastolic", "Respiratory Rate", "SNOMED CT", codes, pct, mode) && ok;
|
|
||||||
} else if (hasSctCode(code, codes, "271306003", "249043002", "444981005", "399017001", "251670001", "429525003", "429614003")) {
|
|
||||||
ok = checkObservationAgainstProfile(valContext,errors, element, stack, "http://hl7.org/fhir/StructureDefinition/heartrate", "Heart rate", "SNOMED CT", codes, pct, mode) && ok;
|
|
||||||
} else if (hasSctCode(code, codes, "103228002", "103228002", "442349007", "442476006", "442440005", "431314004", "442734002", "713194001")) {
|
|
||||||
ok = checkObservationAgainstProfile(valContext,errors, element, stack, "http://hl7.org/fhir/StructureDefinition/oxygensat", "Oxygen saturation", "SNOMED CT", codes, pct, mode) && ok;
|
|
||||||
} else if (hasSctCode(code, codes, "386725007", "276885007", "300076005", "1222808002", "364246006", "307047009", "708499008", "708499008", "431598003", "698831002", "698832009", "415882003", "415974002", "415929009", "415945006")) {
|
|
||||||
ok = checkObservationAgainstProfile(valContext,errors, element, stack, "http://hl7.org/fhir/StructureDefinition/bodytemp", "Body temperature", "SNOMED CT", codes, pct, mode) && ok;
|
|
||||||
} else if (hasSctCode(code, codes, "1153637007", "1162419008", "50373000", "1162418000", "1230278008", "1162392001", "1162417005")) {
|
|
||||||
ok = checkObservationAgainstProfile(valContext,errors, element, stack, "http://hl7.org/fhir/StructureDefinition/bodyheight", "Body height", "SNOMED CT", codes, pct, mode) && ok;
|
|
||||||
} else if (hasSctCode(code, codes, "363812007", "169876006", "1269262007", "363811000")) {
|
|
||||||
ok = checkObservationAgainstProfile(valContext,errors, element, stack, "http://hl7.org/fhir/StructureDefinition/headcircum", "Head circumference", "SNOMED CT", codes, pct, mode) && ok;
|
|
||||||
} else if (hasSctCode(code, codes, "363811000", "60621009", "735395000", "425024002", "424927000", "784399000", "1162416001", "1162415002")) {
|
|
||||||
ok = checkObservationAgainstProfile(valContext,errors, element, stack, "http://hl7.org/fhir/StructureDefinition/bodyweight", "Body weight", "SNOMED CT", codes, pct, mode) && ok;
|
|
||||||
} else if (hasSctCode(code, codes, "60621009")) {
|
|
||||||
ok = checkObservationAgainstProfile(valContext,errors, element, stack, "http://hl7.org/fhir/StructureDefinition/bmi", "Body mass index", "SNOMED CT", codes, pct, mode) && ok;
|
|
||||||
} else if (hasSctCode(code, codes, "75367002", "251076008", "163033001", "163035008", "386534000", "386536003", "271649006", "271649006", "271650006", "407556006", "407554009", "716579001", "399304008")) {
|
|
||||||
ok = checkObservationAgainstProfile(valContext,errors, element, stack, "http://hl7.org/fhir/StructureDefinition/bp", "Blood pressure systolic and diastolic", "SNOMED CT", codes, pct, mode) && ok;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean checkObservationAgainstProfile(ValidationContext valContext, List<ValidationMessage> errors, Element element, NodeStack stack, String url, String name, String sys, List<String> loinc, PercentageTracker pct, ValidationMode mode) {
|
|
||||||
element.addMessage(signpost(errors, NO_RULE_DATE, IssueType.INFORMATIONAL, element.line(), element.col(), stack.getLiteralPath(), I18nConstants.VALIDATION_VAL_PROFILE_SIGNPOST_OBS, url, name, sys, loinc.get(0)));
|
|
||||||
StructureDefinition sd = context.fetchResource(StructureDefinition.class, url);
|
|
||||||
if (sd == null) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
return ((InstanceValidator) parent).startInner(valContext, errors, element, element, sd, stack, false, pct, mode, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean hasLoincCode(Element code, List<String> codes, String... values) {
|
|
||||||
if (code != null) {
|
|
||||||
List<Element> codings = code.getChildren("coding");
|
|
||||||
for (Element coding : codings) {
|
|
||||||
if ("http://loinc.org".equals(coding.getNamedChildValue("system", false)) && Utilities.existsInList(coding.getNamedChildValue("code", false), values)) {
|
|
||||||
codes.add(coding.getNamedChildValue("code", false));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean hasSctCode(Element code, List<String> codes, String... values) {
|
|
||||||
if (code != null) {
|
|
||||||
List<Element> codings = code.getChildren("coding");
|
|
||||||
for (Element coding : codings) {
|
|
||||||
if ("http://snomed.info/sct".equals(coding.getNamedChildValue("system", false)) && Utilities.existsInList(coding.getNamedChildValue("code", false), values)) {
|
|
||||||
codes.add(coding.getNamedChildValue("code", false));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,6 +59,7 @@ import org.hl7.fhir.r5.test.utils.TestingUtilities;
|
||||||
import org.hl7.fhir.r5.utils.OperationOutcomeUtilities;
|
import org.hl7.fhir.r5.utils.OperationOutcomeUtilities;
|
||||||
import org.hl7.fhir.r5.utils.ToolingExtensions;
|
import org.hl7.fhir.r5.utils.ToolingExtensions;
|
||||||
import org.hl7.fhir.r5.utils.validation.BundleValidationRule;
|
import org.hl7.fhir.r5.utils.validation.BundleValidationRule;
|
||||||
|
import org.hl7.fhir.r5.utils.validation.IMessagingServices;
|
||||||
import org.hl7.fhir.r5.utils.validation.IResourceValidator;
|
import org.hl7.fhir.r5.utils.validation.IResourceValidator;
|
||||||
import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor;
|
import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor;
|
||||||
import org.hl7.fhir.r5.utils.validation.IValidatorResourceFetcher;
|
import org.hl7.fhir.r5.utils.validation.IValidatorResourceFetcher;
|
||||||
|
@ -90,6 +91,7 @@ import org.hl7.fhir.validation.ValidationEngine;
|
||||||
import org.hl7.fhir.validation.ValidatorUtils;
|
import org.hl7.fhir.validation.ValidatorUtils;
|
||||||
import org.hl7.fhir.validation.cli.model.HtmlInMarkdownCheck;
|
import org.hl7.fhir.validation.cli.model.HtmlInMarkdownCheck;
|
||||||
import org.hl7.fhir.validation.cli.services.StandAloneValidatorFetcher;
|
import org.hl7.fhir.validation.cli.services.StandAloneValidatorFetcher;
|
||||||
|
import org.hl7.fhir.validation.instance.BasePolicyAdvisorForFullValidation;
|
||||||
import org.hl7.fhir.validation.instance.InstanceValidator;
|
import org.hl7.fhir.validation.instance.InstanceValidator;
|
||||||
import org.hl7.fhir.validation.tests.utilities.TestUtilities;
|
import org.hl7.fhir.validation.tests.utilities.TestUtilities;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
|
@ -469,7 +471,7 @@ public class ValidationTests implements IEvaluationContext, IValidatorResourceFe
|
||||||
}
|
}
|
||||||
|
|
||||||
private ValidationEngine buildVersionEngine(String ver, String txLog) throws Exception {
|
private ValidationEngine buildVersionEngine(String ver, String txLog) throws Exception {
|
||||||
String server = FhirSettings.getTxFhirLocal();
|
String server = FhirSettings.getTxFhirDevelopment();
|
||||||
switch (ver) {
|
switch (ver) {
|
||||||
case "1.0": return TestUtilities.getValidationEngine("hl7.fhir.r2.core#1.0.2", server, txLog, FhirPublication.DSTU2, true, "1.0.2");
|
case "1.0": return TestUtilities.getValidationEngine("hl7.fhir.r2.core#1.0.2", server, txLog, FhirPublication.DSTU2, true, "1.0.2");
|
||||||
case "1.4": return TestUtilities.getValidationEngine("hl7.fhir.r2b.core#1.4.0", server, txLog, FhirPublication.DSTU2016May, true, "1.4.0");
|
case "1.4": return TestUtilities.getValidationEngine("hl7.fhir.r2b.core#1.4.0", server, txLog, FhirPublication.DSTU2016May, true, "1.4.0");
|
||||||
|
@ -887,4 +889,12 @@ public class ValidationTests implements IEvaluationContext, IValidatorResourceFe
|
||||||
public Set<String> fetchCanonicalResourceVersions(IResourceValidator validator, Object appContext, String url) {
|
public Set<String> fetchCanonicalResourceVersions(IResourceValidator validator, Object appContext, String url) {
|
||||||
return new HashSet<>();
|
return new HashSet<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<StructureDefinition> getImpliedProfilesForResource(IResourceValidator validator, Object appContext,
|
||||||
|
String stackPath, ElementDefinition definition, StructureDefinition structure, Element resource, boolean valid,
|
||||||
|
IMessagingServices msgServices, List<ValidationMessage> messages) {
|
||||||
|
return new BasePolicyAdvisorForFullValidation().getImpliedProfilesForResource(validator, appContext, stackPath,
|
||||||
|
definition, structure, resource, valid, msgServices, messages);
|
||||||
|
}
|
||||||
}
|
}
|
2
pom.xml
2
pom.xml
|
@ -21,7 +21,7 @@
|
||||||
<commons_compress_version>1.26.0</commons_compress_version>
|
<commons_compress_version>1.26.0</commons_compress_version>
|
||||||
<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.5.10</validator_test_case_version>
|
<validator_test_case_version>1.5.11-SNAPSHOT</validator_test_case_version>
|
||||||
<jackson_version>2.17.0</jackson_version>
|
<jackson_version>2.17.0</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>
|
||||||
|
|
Loading…
Reference in New Issue