From 59da23070215f5ecf137ce711b55625c1064a261 Mon Sep 17 00:00:00 2001
From: jamesagnew
Date: Tue, 5 Jan 2016 07:20:54 -0500
Subject: [PATCH] Improving validation documentation
---
.../main/java/example/ValidatorExamples.java | 40 +++++
.../uhn/fhir/validation/IValidatorModule.java | 18 +-
.../fhir/validation/SchemaBaseValidator.java | 2 +-
.../validation/FhirInstanceValidatorTest.java | 29 +++-
src/site/xdoc/doc_rest_server_interceptor.xml | 4 +-
src/site/xdoc/doc_validation.xml | 157 ++++++++++--------
6 files changed, 177 insertions(+), 73 deletions(-)
diff --git a/examples/src/main/java/example/ValidatorExamples.java b/examples/src/main/java/example/ValidatorExamples.java
index 49e368e410f..a38dcaf7a5b 100644
--- a/examples/src/main/java/example/ValidatorExamples.java
+++ b/examples/src/main/java/example/ValidatorExamples.java
@@ -29,12 +29,43 @@ import ca.uhn.fhir.parser.StrictErrorHandler;
import ca.uhn.fhir.rest.client.IGenericClient;
import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.validation.FhirValidator;
+import ca.uhn.fhir.validation.IValidatorModule;
+import ca.uhn.fhir.validation.SchemaBaseValidator;
import ca.uhn.fhir.validation.SingleValidationMessage;
import ca.uhn.fhir.validation.ValidationResult;
+import ca.uhn.fhir.validation.schematron.SchematronBaseValidator;
@SuppressWarnings("serial")
public class ValidatorExamples {
+ public void validationIntro() {
+ // START SNIPPET: validationIntro
+ FhirContext ctx = FhirContext.forDstu2();
+
+ // Ask the context for a validator
+ FhirValidator validator = ctx.newValidator();
+
+ // Create some modules and register them
+ IValidatorModule module1 = new SchemaBaseValidator(ctx);
+ validator.registerValidatorModule(module1);
+ IValidatorModule module2 = new SchematronBaseValidator(ctx);
+ validator.registerValidatorModule(module2);
+
+ // Pass a resource in to be validated. The resource can
+ // be an IBaseResource instance, or can be a raw String
+ // containing a serialized resource as text.
+ Patient resource = new Patient();
+ ValidationResult result = validator.validateWithResult(resource);
+ String resourceText = "";
+ ValidationResult result2 = validator.validateWithResult(resourceText);
+
+ // The result object now contains the validation results
+ for (SingleValidationMessage next : result.getMessages()) {
+ System.out.println(next.getLocationString() + " " + next.getMessage());
+ }
+ // END SNIPPET: validationIntro
+ }
+
// START SNIPPET: serverValidation
public class MyRestfulServer extends RestfulServer {
@@ -96,6 +127,15 @@ public class ValidatorExamples {
// Request a validator and apply it
FhirValidator val = ctx.newValidator();
+ // Create the Schema/Schematron modules and register them. Note that
+ // you might want to consider keeping these modules around as long-term
+ // objects: they parse and then store schemas, which can be an expensive
+ // operation.
+ IValidatorModule module1 = new SchemaBaseValidator(ctx);
+ IValidatorModule module2 = new SchematronBaseValidator(ctx);
+ val.registerValidatorModule(module1);
+ val.registerValidatorModule(module2);
+
ValidationResult result = val.validateWithResult(p);
if (result.isSuccessful()) {
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/IValidatorModule.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/IValidatorModule.java
index bf3c84bf19f..2872920867e 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/IValidatorModule.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/IValidatorModule.java
@@ -26,12 +26,28 @@ import ca.uhn.fhir.model.api.Bundle;
*/
/**
- * Registers
+ * An individual validation module, which applies validation rules against
+ * resources and adds failure/informational messages as it goes.
+ *
+ * See Validation
+ * for a list of available modules. You may also create your own.
*/
public interface IValidatorModule {
+ /**
+ * Validate the actual resource.
+ *
+ * The {@link IValidationContext} can be used to access the resource being validated,
+ * and is populated with the results.
+ */
void validateResource(IValidationContext theCtx);
+ /**
+ * This method applies only to DSTU1 Atom Bundles. All other validation will pass through
+ * {@link #validateResource(IValidationContext)} inclusing DSTU2+ Bundle resources. If you
+ * will not be validating DSTU1 Bundles, you may implement this method as
+ * a NO-OP.
+ */
void validateBundle(IValidationContext theContext);
}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/SchemaBaseValidator.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/SchemaBaseValidator.java
index cebd80a4693..2a720404fda 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/SchemaBaseValidator.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/SchemaBaseValidator.java
@@ -75,7 +75,7 @@ public class SchemaBaseValidator implements IValidatorModule {
private Map myKeyToSchema = new HashMap();
private FhirContext myCtx;
- SchemaBaseValidator(FhirContext theContext) {
+ public SchemaBaseValidator(FhirContext theContext) {
myCtx = theContext;
}
diff --git a/hapi-fhir-structures-dstu2.1/src/test/java/ca/uhn/fhir/validation/FhirInstanceValidatorTest.java b/hapi-fhir-structures-dstu2.1/src/test/java/ca/uhn/fhir/validation/FhirInstanceValidatorTest.java
index e95ee60fd8e..9f14076b0b8 100644
--- a/hapi-fhir-structures-dstu2.1/src/test/java/ca/uhn/fhir/validation/FhirInstanceValidatorTest.java
+++ b/hapi-fhir-structures-dstu2.1/src/test/java/ca/uhn/fhir/validation/FhirInstanceValidatorTest.java
@@ -11,8 +11,10 @@ import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import org.apache.commons.io.IOUtils;
import org.hl7.fhir.dstu21.hapi.validation.DefaultProfileValidationSupport;
@@ -51,9 +53,11 @@ public class FhirInstanceValidatorTest {
private FhirValidator myVal;
private ArrayList myValidConcepts;
+ private Set myValidSystems = new HashSet();
private Map mySupportedCodeSystemsForExpansion;
private void addValidConcept(String theSystem, String theCode) {
+ myValidSystems.add(theSystem);
myValidConcepts.add(theSystem + "___" + theCode);
}
@@ -87,8 +91,8 @@ public class FhirInstanceValidatorTest {
when(myMockSupport.isCodeSystemSupported(any(FhirContext.class), any(String.class))).thenAnswer(new Answer() {
@Override
public Boolean answer(InvocationOnMock theInvocation) throws Throwable {
- boolean retVal = mySupportedCodeSystemsForExpansion.containsKey(theInvocation.getArguments()[0]);
- ourLog.info("isCodeSystemSupported({}) : {}", new Object[] { theInvocation.getArguments()[0], retVal });
+ boolean retVal = myValidSystems.contains(theInvocation.getArguments()[1]);
+ ourLog.info("isCodeSystemSupported({}) : {}", new Object[] { theInvocation.getArguments()[1], retVal });
return retVal;
}
});
@@ -289,6 +293,27 @@ public class FhirInstanceValidatorTest {
assertThat(errors.toString(), containsString(""));
}
+ @Test
+ public void testValidateResourceContainingLoincCode() {
+ addValidConcept("http://loinc.org", "1234567");
+
+ Observation input = new Observation();
+// input.getMeta().addProfile("http://hl7.org/fhir/StructureDefinition/devicemetricobservation");
+
+ input.addIdentifier().setSystem("http://acme").setValue("12345");
+ input.getEncounter().setReference("http://foo.com/Encounter/9");
+ input.setStatus(ObservationStatus.FINAL);
+ input.getCode().addCoding().setSystem("http://loinc.org").setCode("12345");
+
+ myInstanceVal.setValidationSupport(myMockSupport);
+ ValidationResult output = myVal.validateWithResult(input);
+ List errors = logResultsAndReturnAll(output);
+
+ assertThat(errors.toString(), containsString("information"));
+ assertThat(errors.toString(), containsString("Unknown code: http://loinc.org / 12345"));
+ assertEquals(1, errors.size());
+ }
+
@Test
public void testValidateResourceWithDefaultValueset() {
Observation input = new Observation();
diff --git a/src/site/xdoc/doc_rest_server_interceptor.xml b/src/site/xdoc/doc_rest_server_interceptor.xml
index 37d0bf15aa3..d451941af40 100644
--- a/src/site/xdoc/doc_rest_server_interceptor.xml
+++ b/src/site/xdoc/doc_rest_server_interceptor.xml
@@ -273,7 +273,9 @@
See the Validation Page for information on
- available IValidationModule validation modules. Any of the Resource Validators
+ available
+ IValidatorModule
+ validation modules. Any of the Resource Validators
listed on that page can be enabled in these interceptors (note that the Parser Validators
can not).
diff --git a/src/site/xdoc/doc_validation.xml b/src/site/xdoc/doc_validation.xml
index 7de39533ba3..8f7c50503a4 100644
--- a/src/site/xdoc/doc_validation.xml
+++ b/src/site/xdoc/doc_validation.xml
@@ -14,6 +14,12 @@
sections below.
+ -
+ Resource Validation
+ is validation of the raw or parsed resource against
+ the official FHIR validation rules (e.g. Schema/Schematron/Profile/StructureDefinition/ValueSet)
+ as well as against custom profiles which have been developed.
+
-
Parser Validation
is validation at runtime during the parsing
@@ -25,85 +31,40 @@
that no data is being lost during parsing, but is less comprehensive than resource validation
against raw text data.
- -
- Resource Validation
- is validation of the raw or parsed resource against
- the official FHIR validation rules (e.g. Schema/Schematron/Profile/StructureDefinition/ValueSet).
-
-
-
-
- Parser validation is controlled by calling
- setParserErrorHandler(IParserErrorHandler)
- on
- either the FhirContext or on individual parser instances. This method
- takes an
- IParserErrorHandler
- , which is a callback that
- will be invoked any time a parse issue is detected.
-
-
- There are two implementations of
- IParserErrorHandler
- worth
- mentioning. You can also supply your own implementation if you want.
-
-
- -
- LenientErrorHandler
- logs any errors but does not abort parsing. By default this handler is used, and it
- logs errors at "warning" level. It can also be configured to silently
- ignore issues.
-
- -
- StrictErrorHandler
- throws a
-
DataFormatException
- if any errors are detected.
-
-
-
-
- The following example shows how to configure a parser to use strict validation.
-
-
-
-
-
-
-
- You can also configure the error handler at the FhirContext level, which is useful
- for clients.
-
-
-
-
-
-
-
- FhirContext level validators can also be useful on servers.
-
-
-
-
-
-
-
-
-
+
HAPI provides a built-in and configurable mechanism for validating resources.
This mechanism is called the
- Resource Validator
- .
+ Resource Validator.
+
+ The resource validator is an extendible and modular system, and you
+ can configure it in a number of ways in order to get the specific
+ type of validation you want to achieve.
+
+
+
+ The validator can be manually invoked at any time by creating a
+ validator and configuring it with one or more
+ IValidatorModule
+ instances.
+
+
+
+
+
+
+
+
+
+
FHIR resource definitions are distributed with a set of XML schema files (XSD)
@@ -262,6 +223,66 @@
+
+
+
+ Parser validation is controlled by calling
+ setParserErrorHandler(IParserErrorHandler)
+ on
+ either the FhirContext or on individual parser instances. This method
+ takes an
+ IParserErrorHandler
+ , which is a callback that
+ will be invoked any time a parse issue is detected.
+
+
+ There are two implementations of
+ IParserErrorHandler
+ worth
+ mentioning. You can also supply your own implementation if you want.
+
+
+ -
+ LenientErrorHandler
+ logs any errors but does not abort parsing. By default this handler is used, and it
+ logs errors at "warning" level. It can also be configured to silently
+ ignore issues.
+
+ -
+ StrictErrorHandler
+ throws a
+
DataFormatException
+ if any errors are detected.
+
+
+
+
+ The following example shows how to configure a parser to use strict validation.
+
+
+
+
+
+
+
+ You can also configure the error handler at the FhirContext level, which is useful
+ for clients.
+
+
+
+
+
+
+
+ FhirContext level validators can also be useful on servers.
+
+
+
+
+
+
+
+