diff --git a/hapi-fhir-docs/src/main/java/ca/uhn/hapi/fhir/docs/RepositoryValidatingInterceptorExamples.java b/hapi-fhir-docs/src/main/java/ca/uhn/hapi/fhir/docs/RepositoryValidatingInterceptorExamples.java index 89eb0360318..896f021375e 100644 --- a/hapi-fhir-docs/src/main/java/ca/uhn/hapi/fhir/docs/RepositoryValidatingInterceptorExamples.java +++ b/hapi-fhir-docs/src/main/java/ca/uhn/hapi/fhir/docs/RepositoryValidatingInterceptorExamples.java @@ -28,6 +28,7 @@ import ca.uhn.fhir.jpa.interceptor.validation.RepositoryValidatingRuleBuilder; import ca.uhn.fhir.validation.ResultSeverityEnum; import org.springframework.context.ApplicationContext; +import javax.annotation.Nonnull; import java.util.List; @SuppressWarnings("unused") @@ -107,11 +108,44 @@ public class RepositoryValidatingInterceptorExamples { ruleBuilder .forResourcesOfType("Patient") .requireValidationToDeclaredProfiles() - .dontReject() + .neverReject() .tagOnSeverity(ResultSeverityEnum.ERROR, "http://example.com", "validation-failure"); //END SNIPPET: requireValidationToDeclaredProfilesTagOnFailure } + public void requireValidationToDeclaredProfilesAdditionalOptions() { + RepositoryValidatingRuleBuilder ruleBuilder = myAppCtx.getBean(RepositoryValidatingRuleBuilder.class); + + //START SNIPPET: requireValidationToDeclaredProfilesAdditionalOptions + ruleBuilder + .forResourcesOfType("Patient") + .requireValidationToDeclaredProfiles() + + // Configure the validator to never reject extensions + .allowAnyExtensions() + + // Configure the validator to not perform terminology validation + .disableTerminologyChecks() + + // Configure the validator to raise an error if a resource being + // validated declares a profile, and the StructureDefinition for + // this profile can not be found. + .errorOnUnknownProfiles() + + // Configure the validator to suppress the information-level + // message that is added to the validation result if a profile + // StructureDefinition does not declare a binding for a coded + // field. + .suppressNoBindingMessage() + + // Configure the validator to suppress the warning-level message + // that is added when validating a code that can't be found in a + // ValueSet that has an extensible binding. + .suppressWarningForExtensibleValueSetValidation(); + //END SNIPPET: requireValidationToDeclaredProfilesAdditionalOptions + } + + public void disallowProfiles() { RepositoryValidatingRuleBuilder ruleBuilder = myAppCtx.getBean(RepositoryValidatingRuleBuilder.class); diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/validation/repository_validating_interceptor.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/validation/repository_validating_interceptor.md index 1368526eeb5..7c26bd43c21 100644 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/validation/repository_validating_interceptor.md +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/validation/repository_validating_interceptor.md @@ -95,6 +95,13 @@ By default, resource updates/changes resulting in failing validation will cause {{snippet:classpath:/ca/uhn/hapi/fhir/docs/RepositoryValidatingInterceptorExamples.java|requireValidationToDeclaredProfilesTagOnFailure}} ``` +## Configuring the Validator + +The following snippet shows a number of additional optional settings that can be chained onto the validation rule. + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/RepositoryValidatingInterceptorExamples.java|requireValidationToDeclaredProfilesAdditionalOptions}} +``` # Rules: Disallow Specific Profiles diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/interceptor/validation/RepositoryValidatingRuleBuilder.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/interceptor/validation/RepositoryValidatingRuleBuilder.java index 2f79c4534c8..fbe10366af2 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/interceptor/validation/RepositoryValidatingRuleBuilder.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/interceptor/validation/RepositoryValidatingRuleBuilder.java @@ -226,7 +226,7 @@ public final class RepositoryValidatingRuleBuilder implements IRuleRoot { * Specifies that the resource should not be rejected from storage even if it does not pass validation. */ @Nonnull - public FinalizedRequireValidationRule dontReject() { + public FinalizedRequireValidationRule neverReject() { myRule.dontReject(); return this; } @@ -292,6 +292,57 @@ public final class RepositoryValidatingRuleBuilder implements IRuleRoot { return this; } + /** + * Configure the validator to never reject extensions + */ + @Nonnull + public FinalizedRequireValidationRule allowAnyExtensions() { + myRule.getValidator().setAnyExtensionsAllowed(true); + return this; + } + + /** + * Configure the validator to not perform terminology validation + */ + @Nonnull + public FinalizedRequireValidationRule disableTerminologyChecks() { + myRule.getValidator().setNoTerminologyChecks(true); + return this; + } + + /** + * Configure the validator to raise an error if a resource being validated + * declares a profile, and the StructureDefinition for this profile + * can not be found. + */ + @Nonnull + public FinalizedRequireValidationRule errorOnUnknownProfiles() { + myRule.getValidator().setErrorForUnknownProfiles(true); + return this; + } + + /** + * Configure the validator to suppress the information-level message that + * is added to the validation result if a profile StructureDefinition does + * not declare a binding for a coded field. + */ + @Nonnull + public FinalizedRequireValidationRule suppressNoBindingMessage() { + myRule.getValidator().setNoBindingMsgSuppressed(true); + return this; + } + + /** + * Configure the validator to suppress the warning-level message that + * is added when validating a code that can't be found in an ValueSet that + * has an extensible binding. + */ + @Nonnull + public FinalizedRequireValidationRule suppressWarningForExtensibleValueSetValidation() { + myRule.getValidator().setNoExtensibleWarnings(true); + return this; + } + } } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/interceptor/validation/RequireValidationRule.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/interceptor/validation/RequireValidationRule.java index fb5f5f9847b..2d4857332be 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/interceptor/validation/RequireValidationRule.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/interceptor/validation/RequireValidationRule.java @@ -117,6 +117,14 @@ class RequireValidationRule extends BaseTypedRule { .toString(); } + public FhirInstanceValidator getValidator() { + return myValidator; + } + + public void setAllowAnyExtensions() { + myValidator.setAnyExtensionsAllowed(true); + } + private static class TagOnSeverity { private final int mySeverity; private final String myTagSystem; diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/interceptor/validation/RepositoryValidatingInterceptorR4Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/interceptor/validation/RepositoryValidatingInterceptorR4Test.java index 6a9b8d5b652..d48e9cbe61f 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/interceptor/validation/RepositoryValidatingInterceptorR4Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/interceptor/validation/RepositoryValidatingInterceptorR4Test.java @@ -264,13 +264,40 @@ public class RepositoryValidatingInterceptorR4Test extends BaseJpaR4Test { } } + @Test + public void testRequireValidation_AdditionalOptions() { + List rules = newRuleBuilder() + .forResourcesOfType("Observation") + .requireValidationToDeclaredProfiles() + .withBestPracticeWarningLevel("IGNORE") + .allowAnyExtensions() + .disableTerminologyChecks() + .errorOnUnknownProfiles() + .suppressNoBindingMessage() + .suppressWarningForExtensibleValueSetValidation() + .build(); + + myValInterceptor.setRules(rules); + + Observation obs = new Observation(); + obs.getCode().addCoding().setSystem("http://foo").setCode("123").setDisplay("help im a bug"); + obs.setStatus(Observation.ObservationStatus.AMENDED); + try { + IIdType id = myObservationDao.create(obs).getId(); + assertEquals("1", id.getVersionIdPart()); + } catch (PreconditionFailedException e) { + // should not happen + fail(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(e.getOperationOutcome())); + } + } + @Test public void testRequireValidation_FailNoRejectAndTag() { List rules = newRuleBuilder() .forResourcesOfType("Observation") .requireValidationToDeclaredProfiles() .withBestPracticeWarningLevel("IGNORE") - .dontReject() + .neverReject() .tagOnSeverity(ResultSeverityEnum.ERROR, "http://foo", "validation-error") .build(); myValInterceptor.setRules(rules);