This commit is contained in:
miantorno 2015-09-04 09:08:07 -04:00
commit e3c3600700
10 changed files with 260 additions and 72 deletions

View File

@ -30,6 +30,11 @@
<artifactId>hapi-fhir-structures-hl7org-dstu2</artifactId>
<version>1.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-validation-resources-dstu2</artifactId>
<version>1.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>

View File

@ -8,17 +8,22 @@ import javax.servlet.ServletException;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.filefilter.WildcardFileFilter;
import org.hl7.fhir.instance.model.ValueSet;
import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.dstu2.resource.Observation;
import ca.uhn.fhir.model.dstu2.resource.OperationOutcome;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.dstu2.valueset.ContactPointSystemEnum;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.parser.IParser;
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.FhirInstanceValidator;
import ca.uhn.fhir.validation.FhirValidator;
import ca.uhn.fhir.validation.IValidationSupport;
import ca.uhn.fhir.validation.SingleValidationMessage;
import ca.uhn.fhir.validation.ValidationResult;
@ -114,10 +119,88 @@ public class ValidatorExamples {
}
public static void main(String[] args) throws Exception {
validateFiles();
instanceValidator();
}
private static void instanceValidator() throws Exception {
// START SNIPPET: instanceValidator
FhirContext ctx = FhirContext.forDstu2();
// Create a FhirInstanceValidator and register it to a validator
FhirValidator validator = ctx.newValidator();
FhirInstanceValidator instanceValidator = new FhirInstanceValidator();
validator.registerValidatorModule(instanceValidator);
/*
* Let's create a resource to validate. This Observation has some fields
* populated, but it is missing Observation.status, which is mandatory.
*/
Observation obs = new Observation();
obs.getCode().addCoding().setSystem("http://loinc.org").setCode("12345-6");
obs.setValue(new StringDt("This is a value"));
// Validate
ValidationResult result = validator.validateWithResult(obs);
// Do we have any errors or fatal errors?
System.out.println(result.isSuccessful()); // false
// Show the issues
for (SingleValidationMessage next : result.getMessages()) {
System.out.println(" Next issue " + next.getSeverity() + " - " + next.getLocationString() + " - " + next.getMessage());
}
// Prints:
// Next issue ERROR - /f:Observation - Element '/f:Observation.status': minimum required = 1, but only found 0
// Next issue WARNING - /f:Observation/f:code - Unable to validate code "12345-6" in code system "http://loinc.org"
// You can also convert the result into an operation outcome if you
// need to return one from a server
OperationOutcome oo = (OperationOutcome) result.toOperationOutcome();
// END SNIPPET: instanceValidator
}
private static void instanceValidatorCustom() throws Exception {
// START SNIPPET: instanceValidatorCustom
FhirContext ctx = FhirContext.forDstu2();
// Create a FhirInstanceValidator and register it to a validator
FhirValidator validator = ctx.newValidator();
FhirInstanceValidator instanceValidator = new FhirInstanceValidator();
validator.registerValidatorModule(instanceValidator);
IValidationSupport valSupport = new IValidationSupport() {
@Override
public org.hl7.fhir.instance.utils.IWorkerContext.ValidationResult validateCode(String theCodeSystem, String theCode, String theDisplay) {
// TODO: Implement
return null;
}
@Override
public boolean isCodeSystemSupported(String theSystem) {
// TODO: Implement
return false;
}
@Override
public <T extends IBaseResource> T fetchResource(FhirContext theContext, Class<T> theClass, String theUri) {
// TODO: Implement
return null;
}
@Override
public ValueSet fetchCodeSystem(String theSystem) {
// TODO: Implement
return null;
}
};
instanceValidator.setValidationSupport(valSupport);
// END SNIPPET: instanceValidatorCustom
}
@SuppressWarnings("unused")
private static void validateFiles() throws Exception {
// START SNIPPET: validateFiles
FhirContext ctx = FhirContext.forDstu2();

View File

@ -54,14 +54,13 @@ public class FhirValidator {
private static volatile Boolean ourPhlocPresentOnClasspath;
private final FhirContext myContext;
private volatile List<IValidatorModule> myValidators = new ArrayList<IValidatorModule>();
private List<IValidatorModule> myValidators = new ArrayList<IValidatorModule>();
/**
* Constructor (this should not be called directly, but rather {@link FhirContext#newValidator()} should be called to obtain an instance of {@link FhirValidator})
*/
public FhirValidator(FhirContext theFhirContext) {
myContext = theFhirContext;
setValidateAgainstStandardSchema(true);
if (ourPhlocPresentOnClasspath == null) {
try {
@ -72,10 +71,6 @@ public class FhirValidator {
ourPhlocPresentOnClasspath = false;
}
}
if (ourPhlocPresentOnClasspath) {
setValidateAgainstStandardSchematron(true);
}
}
private void addOrRemoveValidator(boolean theValidateAgainstStandardSchema, Class<? extends IValidatorModule> type, IValidatorModule theInstance) {
@ -184,6 +179,8 @@ public class FhirValidator {
public void validate(Bundle theBundle) {
Validate.notNull(theBundle, "theBundle must not be null");
applyDefaultValidators();
IValidationContext<Bundle> ctx = ValidationContext.forBundle(myContext, theBundle);
for (IValidatorModule next : myValidators) {
@ -197,6 +194,15 @@ public class FhirValidator {
}
private void applyDefaultValidators() {
if (myValidators.isEmpty()) {
setValidateAgainstStandardSchema(true);
if (ourPhlocPresentOnClasspath) {
setValidateAgainstStandardSchematron(true);
}
}
}
/**
* Validates a resource instance, throwing a {@link ValidationFailureException} if the validation fails
*
@ -208,6 +214,9 @@ public class FhirValidator {
*/
@Deprecated
public void validate(IResource theResource) throws ValidationFailureException {
applyDefaultValidators();
ValidationResult validationResult = validateWithResult(theResource);
if (!validationResult.isSuccessful()) {
throw new ValidationFailureException(myContext, validationResult.toOperationOutcome());
@ -225,6 +234,8 @@ public class FhirValidator {
public ValidationResult validateWithResult(Bundle theBundle) {
Validate.notNull(theBundle, "theBundle must not be null");
applyDefaultValidators();
IValidationContext<Bundle> ctx = ValidationContext.forBundle(myContext, theBundle);
for (IValidatorModule next : myValidators) {
@ -245,6 +256,8 @@ public class FhirValidator {
public ValidationResult validateWithResult(IBaseResource theResource) {
Validate.notNull(theResource, "theResource must not be null");
applyDefaultValidators();
IValidationContext<IBaseResource> ctx = ValidationContext.forResource(myContext, theResource);
for (IValidatorModule next : myValidators) {
@ -265,6 +278,8 @@ public class FhirValidator {
public ValidationResult validateWithResult(String theResource) {
Validate.notNull(theResource, "theResource must not be null");
applyDefaultValidators();
IValidationContext<IBaseResource> ctx = ValidationContext.forText(myContext, theResource);
for (IValidatorModule next : myValidators) {

View File

@ -59,7 +59,10 @@ public class ValidationResult {
}
/**
* Was the validation successful
* Was the validation successful (in other words, do we have no issues that are at
* severity {@link ResultSeverityEnum#ERROR} or {@link ResultSeverityEnum#FATAL}. A validation
* is still considered successful if it only has issues at level {@link ResultSeverityEnum#WARNING} or
* lower.
*
* @return true if the validation was successful
*/

View File

@ -1,11 +1,11 @@
package ca.uhn.fhir.validation;
import static org.junit.Assert.*;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.validation.FhirValidator;
import ca.uhn.fhir.model.dstu.resource.Patient;
public class ValidatorInstantiatorTest {
private static FhirContext ourCtx = FhirContext.forDstu1();
@ -14,6 +14,7 @@ public class ValidatorInstantiatorTest {
public void testValidator() {
FhirValidator val = ourCtx.newValidator();
val.validateWithResult(new Patient());
// We have a full classpath, so take advantage
assertTrue(val.isValidateAgainstStandardSchema());

View File

@ -5,6 +5,7 @@ import static org.junit.Assert.assertTrue;
import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.dstu2.resource.Patient;
public class ValidatorInstantiatorDstu2Test {
@ -13,6 +14,7 @@ public class ValidatorInstantiatorDstu2Test {
public void testValidator() {
FhirValidator val = ourCtx.newValidator();
val.validateWithResult(new Patient());
// We have a full classpath, so take advantage
assertTrue(val.isValidateAgainstStandardSchema());

View File

@ -93,10 +93,17 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IValid
/**
* Returns the "best practice" warning level (default is
* {@link BestPracticeWarningLevel#Hint})
* {@link BestPracticeWarningLevel#Hint}).
* <p>
* The FHIR Instance Validator has
* a number of checks for best practices in terms of FHIR usage. If this setting
* is set to {@link BestPracticeWarningLevel#Error}, any resource data which does not
* meet these best practices will be reported at the ERROR level. If this setting
* is set to {@link BestPracticeWarningLevel#Ignore}, best practice guielines will
* be ignored.
* </p>
*
* @see #setBestPracticeWarningLevel(BestPracticeWarningLevel) for more
* information on this value
* @see {@link #setBestPracticeWarningLevel(BestPracticeWarningLevel)}
*/
public BestPracticeWarningLevel getBestPracticeWarningLevel() {
return myBestPracticeWarningLevel;
@ -115,10 +122,14 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IValid
/**
* Sets the "best practice warning level". When validating, any deviations
* from best practices will be reported at this level.
* {@link BestPracticeWarningLevel#Ignore} means that best practice deviations
* will not be reported, {@link BestPracticeWarningLevel#Warning} means that
* best practice deviations will be reported as warnings, etc. Default is
* {@link BestPracticeWarningLevel#Hint}
* <p>
* The FHIR Instance Validator has
* a number of checks for best practices in terms of FHIR usage. If this setting
* is set to {@link BestPracticeWarningLevel#Error}, any resource data which does not
* meet these best practices will be reported at the ERROR level. If this setting
* is set to {@link BestPracticeWarningLevel#Ignore}, best practice guielines will
* be ignored.
* </p>
*
* @param theBestPracticeWarningLevel
* The level, must not be <code>null</code>

View File

@ -163,7 +163,7 @@
Use the HAPI FHIR client in an application to fetch from or store
resources to an external server.
<br />
<a href="./doc_rest_client.html">Learn Mode</a>
<a href="/hapi-fhir/doc_rest_client.html">Learn Mode</a>
</div></div></foreignObject>
<text x="73" y="45" fill="#4D4D4D" text-anchor="middle"
font-size="12px" font-family="Helvetica">[Not supported by viewer]</text>
@ -266,7 +266,7 @@
Use the HAPI FHIR server in an application to allow external
applications to access or modify your application's data.
<br />
<a href="./doc_rest_server.html">Learn More</a>
<a href="/hapi-fhir/doc_rest_server.html">Learn More</a>
<br />
</div></div></foreignObject>
<text x="73" y="53" fill="#4D4D4D" text-anchor="middle"
@ -382,7 +382,7 @@
Use the HAPI JPA/Database Server to deploy a fully functional FHIR
server you can develop applications against.
<br />
<a href="./doc_jpa.html">Learn More</a>
<a href="/hapi-fhir/doc_jpa.html">Learn More</a>
</div></div></foreignObject>
<text x="73" y="59" fill="#4D4D4D" text-anchor="middle"
font-size="12px" font-family="Helvetica">[Not supported by viewer]</text>
@ -572,7 +572,7 @@
Use the HAPI FHIR parser and encoder to convert between FHIR and
your application's data model.
<br />
<a href="./doc_fhirobjects.html">Learn More</a>
<a href="/hapi-fhir/doc_fhirobjects.html">Learn More</a>
</div></div></foreignObject>
<text x="73" y="45" fill="#4D4D4D" text-anchor="middle"
font-size="12px" font-family="Helvetica">[Not supported by viewer]</text>

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

View File

@ -120,6 +120,8 @@
<item name="Core API" href="./apidocs/index.html" />
<item name="Model API (DSTU1)" href="./apidocs-dstu/index.html" />
<item name="Model API (DSTU2)" href="./apidocs-dstu2/index.html" />
<item name="Model API (RI DSTU2)" href="./apidocs-hl7org-dstu2/index.html" />
<item name="JPA Server API" href="./apidocs-jpaserver/index.html" />
</menu>
<menu name="JXR" inherit="top">
<item name="Core" href="./xref-base/index.html" />

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<document xmlns="http://maven.apache.org/XDOC/2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/XDOC/2.0 http://maven.apache.org/xsd/xdoc-2.0.xsd">
<document xmlns="http://maven.apache.org/XDOC/2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/XDOC/2.0 http://maven.apache.org/xsd/xdoc-2.0.xsd">
<properties>
<title>Validation</title>
@ -16,14 +15,17 @@
</p>
<ul>
<li>
<b>Parser Validation</b> is validation at runtime during the parsing
<b>Parser Validation</b>
is validation at runtime during the parsing
of a resource. It can be used to catch input data that is impossible to
fit into the HAPI data model. For example, it can be used to throw exceptions
fit into the HAPI data model. For
example, it can be used to throw exceptions
or display error messages if a resource being parsed contains tags for which
there are no appropriate fields in a HAPI data structure.
</li>
<li>
<b>Resource Validation</b> is validation of the parsed (or constructed) resource against
<b>Resource Validation</b>
is validation of the parsed (or constructed) resource against
the official FHIR validation rules (e.g. Schema/Schematron).
</li>
</ul>
@ -33,24 +35,33 @@
<section name="Parser Validation">
<p>
Parser validation is controlled by calling <code>setParserErrorHandler(IParserErrorHandler)</code> on
Parser validation is controlled by calling
<code>setParserErrorHandler(IParserErrorHandler)</code>
on
either the FhirContext or on individual parser instances. This method
takes an <code>IParserErrorHandler</code>, which is a callback that
takes an
<code>IParserErrorHandler</code>
, which is a callback that
will be invoked any time a parse issue is detected.
</p>
<p>
There are two implementations of <code>IParserErrorHandler</code> worth
There are two implementations of
<code>IParserErrorHandler</code>
worth
mentioning. You can also supply your own implementation if you want.
</p>
<ul>
<li>
<a href="./apidocs/ca/uhn/fhir/parser/LenientErrorHandler.html">LenientErrorHandler</a>
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.
logs errors at "warning" level. It can also be configured to silently
ignore issues.
</li>
<li>
<a href="./apidocs/ca/uhn/fhir/parser/StrictErrorHandler.html">StrictErrorHandler</a>
throws a <code>DataFormatException</code> if any errors are detected.
throws a
<code>DataFormatException</code>
if any errors are detected.
</li>
</ul>
@ -87,7 +98,9 @@
<p>
HAPI provides a built-in and configurable mechanism for validating resources.
This mechanism is called the <i>Resource Validator</i>.
This mechanism is called the
<i>Resource Validator</i>
.
</p>
<p>
@ -108,12 +121,15 @@
<a href="https://code.google.com/p/phloc-schematron/">Phloc-Schematron</a>
is used, so this library must be added to your classpath (or Maven POM file, Gradle
file, etc.)
Note that this library is specified as an optional dependency by HAPI FHIR
Note that this library is specified as an optional dependency
by HAPI FHIR
so you need to explicitly include it if you want to use this
functionality.
</p>
<p>
See <a href="./download.html">Downloads</a> for more information on how
See
<a href="./download.html">Downloads</a>
for more information on how
to add it.
</p>
</subsection>
@ -123,7 +139,8 @@
<p>
To validate a resource instance, a new validator instance is requested
from the FHIR Context. This validator is then applied against
a specific resource instance, as shown in the example below.
a specific resource
instance, as shown in the example below.
</p>
<macro name="snippet">
<param name="id" value="basicValidation" />
@ -148,13 +165,15 @@
<a name="structure_definition_validation" />
</section>
<section name="Resource Validation (StructureDefinition / ValueSet)">
<section name="Resource Validation (Profile/StructureDefinition)">
<p>
As of HAPI FHIR 1.2, HAPI supports validation against StructureDefinition
resources. This functionality uses the HL7 "InstanceValidator", which is able
to check a resource for conformance to a given profile (StructureDefinition),
including validating codes for conformance to their given ValueSets.
to
check a resource for conformance to a given profile
(StructureDefinitions and ValueSets),
including validating fields, extensions, and codes for conformance to their given ValueSets.
</p>
<p>
StructureDefinition validation can be used to validate a resource against the
@ -170,21 +189,68 @@
</p>
<ul>
<li>
<b>hapi-fhir-structures-hl7org-dstu2</b>: This file contains the "reference implementation"
<b>hapi-fhir-structures-hl7org-dstu2</b>
: This file contains the "reference implementation"
structures and tooling. You need to include it even if you are not using the RI model
(the StructureDefinition validation will work against HAPI structures as well)
</li>
<li>
<b>hapi-fhir-validation-resources-dstu2</b>: This file contains the official FHIR
<b>hapi-fhir-validation-resources-dstu2</b>
: This file contains the official FHIR
StructureDefinition files, and the ValueSets needed to support them.
</li>
</ul>
<p>
See the <a href="./download.html">download page</a> for more information.
See the
<a href="./download.html">download page</a>
for more information.
</p>
</subsection>
<subsection name="Running the Validator">
<p>
To execute the validator, you simply create an instance of
<a href="./apidocs-hl7org-dstu2/ca/uhn/fhir/validation/FhirInstanceValidator.html">FhirInstanceValidator</a>
and register it to new validator, as shown in the example below.
</p>
<p>
Note that the example below uses the official FHIR StructureDefintions and ValueSets
to validate the resource. It will not work unless you include the
<code>hapi-fhir-validation-resources-[version].jar</code> to your classpath.
</p>
<macro name="snippet">
<param name="id" value="instanceValidator" />
<param name="file" value="examples/src/main/java/example/ValidatorExamples.java" />
</macro>
</subsection>
<subsection name="Supplying your own StructureDefinitions">
<p>
The FhirInstanceValidator relies on the
<a href="./apidocs-hl7org-dstu2/ca/uhn/fhir/validation/IValidationSupport.html">IValidationSupport</a>
interface to load StructureDefinitions, and validate codes.
</p>
<p>
By default, the
<a href="./apidocs-hl7org-dstu2/ca/uhn/fhir/validation/DefaultProfileValidationSupport.html">DefaultProfileValidationSupport</a>
implementation is used. This implementation loads the FHIR profiles from the
validator resources JAR. If you want to use your own profiles, you may wish to
supply your own implementation.
</p>
<macro name="snippet">
<param name="id" value="instanceValidatorCustom" />
<param name="file" value="examples/src/main/java/example/ValidatorExamples.java" />
</macro>
</subsection>
</section>
</body>