All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ca.uhn.fhir.validation.FhirValidator Maven / Gradle / Ivy

There is a newer version: 7.6.1
Show newest version
package ca.uhn.fhir.validation;

/*
 * #%L
 * HAPI FHIR - Core Library
 * %%
 * Copyright (C) 2014 - 2016 University Health Network
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
import org.hl7.fhir.instance.model.api.IBaseResource;

import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.util.OperationOutcomeUtil;
import ca.uhn.fhir.validation.schematron.SchematronProvider;

/**
 * Resource validator, which checks resources for compliance against various validation schemes (schemas, schematrons, profiles, etc.)
 * 
 * 

* To obtain a resource validator, call {@link FhirContext#newValidator()} *

* *

* Thread safety note: This class is thread safe, so you may register or unregister validator modules at any time. Individual modules are not guaranteed to be thread safe however. Reconfigure * them with caution. *

*/ public class FhirValidator { private static final String I18N_KEY_NO_PHLOC_ERROR = FhirValidator.class.getName() + ".noPhlocError"; private static volatile Boolean ourPhlocPresentOnClasspath; private final FhirContext myContext; private List myValidators = new ArrayList(); /** * 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; if (ourPhlocPresentOnClasspath == null) { ourPhlocPresentOnClasspath = SchematronProvider.isSchematronAvailable(theFhirContext); } } private void addOrRemoveValidator(boolean theValidateAgainstStandardSchema, Class type, IValidatorModule theInstance) { if (theValidateAgainstStandardSchema) { boolean found = haveValidatorOfType(type); if (!found) { registerValidatorModule(theInstance); } } else { for (Iterator iter = myValidators.iterator(); iter.hasNext();) { IValidatorModule next = iter.next(); if (next.getClass().equals(type)) { unregisterValidatorModule(next); } } } } private boolean haveValidatorOfType(Class type) { boolean found = false; for (IValidatorModule next : myValidators) { if (next.getClass().equals(type)) { found = true; } } return found; } /** * Should the validator validate the resource against the base schema (the schema provided with the FHIR distribution itself) */ public synchronized boolean isValidateAgainstStandardSchema() { return haveValidatorOfType(SchemaBaseValidator.class); } /** * Should the validator validate the resource against the base schema (the schema provided with the FHIR distribution itself) */ public synchronized boolean isValidateAgainstStandardSchematron() { if (!ourPhlocPresentOnClasspath) { return false; // No need to ask since we dont have Phloc. Also Class.forname will complain // about missing phloc import. } Class cls = SchematronProvider.getSchematronValidatorClass(); return haveValidatorOfType(cls); } /** * Add a new validator module to this validator. You may register as many modules as you like at any time. * * @param theValidator * The validator module. Must not be null. */ public synchronized void registerValidatorModule(IValidatorModule theValidator) { Validate.notNull(theValidator, "theValidator must not be null"); ArrayList newValidators = new ArrayList(myValidators.size() + 1); newValidators.addAll(myValidators); newValidators.add(theValidator); myValidators = newValidators; } /** * Should the validator validate the resource against the base schema (the schema provided with the FHIR distribution itself) * * @return Returns a referens to this for method chaining */ public synchronized FhirValidator setValidateAgainstStandardSchema(boolean theValidateAgainstStandardSchema) { addOrRemoveValidator(theValidateAgainstStandardSchema, SchemaBaseValidator.class, new SchemaBaseValidator(myContext)); return this; } /** * Should the validator validate the resource against the base schematron (the schematron provided with the FHIR distribution itself) * * @return Returns a referens to this for method chaining */ public synchronized FhirValidator setValidateAgainstStandardSchematron(boolean theValidateAgainstStandardSchematron) { if (theValidateAgainstStandardSchematron && !ourPhlocPresentOnClasspath) { throw new IllegalArgumentException(myContext.getLocalizer().getMessage(I18N_KEY_NO_PHLOC_ERROR)); } Class cls = SchematronProvider.getSchematronValidatorClass(); IValidatorModule instance = SchematronProvider.getSchematronValidatorInstance(myContext); addOrRemoveValidator(theValidateAgainstStandardSchematron, cls, instance); return this; } /** * Removes a validator module from this validator. You may register as many modules as you like, and remove them at any time. * * @param theValidator * The validator module. Must not be null. */ public synchronized void unregisterValidatorModule(IValidatorModule theValidator) { Validate.notNull(theValidator, "theValidator must not be null"); ArrayList newValidators = new ArrayList(myValidators.size() + 1); newValidators.addAll(myValidators); newValidators.remove(theValidator); myValidators = newValidators; } /** * Validates a bundle instance, throwing a {@link ValidationFailureException} if the validation fails. This validation includes validation of all resources in the bundle. * * @param theBundle * The resource to validate * @throws ValidationFailureException * If the validation fails * @deprecated use {@link #validateWithResult(ca.uhn.fhir.model.api.Bundle)} instead */ @Deprecated public void validate(Bundle theBundle) { Validate.notNull(theBundle, "theBundle must not be null"); applyDefaultValidators(); IValidationContext ctx = ValidationContext.forBundle(myContext, theBundle); for (IValidatorModule next : myValidators) { next.validateBundle(ctx); } if (ctx.toResult().isSuccessful() == false ) { IBaseOperationOutcome oo = ctx.toResult().toOperationOutcome(); if (oo != null && OperationOutcomeUtil.hasIssues(myContext, oo)) { throw new ValidationFailureException(myContext, oo); } } } private void applyDefaultValidators() { if (myValidators.isEmpty()) { setValidateAgainstStandardSchema(true); if (ourPhlocPresentOnClasspath) { setValidateAgainstStandardSchematron(true); } } } /** * Validates a resource instance, throwing a {@link ValidationFailureException} if the validation fails * * @param theResource * The resource to validate * @throws ValidationFailureException * If the validation fails * @deprecated use {@link #validateWithResult(IBaseResource)} instead */ @Deprecated public void validate(IResource theResource) throws ValidationFailureException { applyDefaultValidators(); ValidationResult validationResult = validateWithResult(theResource); if (!validationResult.isSuccessful()) { throw new ValidationFailureException(myContext, validationResult.toOperationOutcome()); } } /** * Validates a bundle instance returning a {@link ca.uhn.fhir.validation.ValidationResult} which contains the results. This validation includes validation of all resources in the bundle. * * @param theBundle * the bundle to validate * @return the results of validation * @since 0.7 */ public ValidationResult validateWithResult(Bundle theBundle) { Validate.notNull(theBundle, "theBundle must not be null"); applyDefaultValidators(); IValidationContext ctx = ValidationContext.forBundle(myContext, theBundle); for (IValidatorModule next : myValidators) { next.validateBundle(ctx); } return ctx.toResult(); } /** * Validates a resource instance returning a {@link ca.uhn.fhir.validation.ValidationResult} which contains the results. * * @param theResource * the resource to validate * @return the results of validation * @since 0.7 */ public ValidationResult validateWithResult(IBaseResource theResource) { Validate.notNull(theResource, "theResource must not be null"); applyDefaultValidators(); IValidationContext ctx = ValidationContext.forResource(myContext, theResource); for (IValidatorModule next : myValidators) { next.validateResource(ctx); } return ctx.toResult(); } /** * Validates a resource instance returning a {@link ca.uhn.fhir.validation.ValidationResult} which contains the results. * * @param theResource * the resource to validate * @return the results of validation * @since 1.1 */ public ValidationResult validateWithResult(String theResource) { Validate.notNull(theResource, "theResource must not be null"); applyDefaultValidators(); IValidationContext ctx = ValidationContext.forText(myContext, theResource); for (IValidatorModule next : myValidators) { next.validateResource(ctx); } return ctx.toResult(); } }