Moved concurrent details from ValidationOptions to FhirValidator

This commit is contained in:
Ken Stevens 2021-11-07 15:04:33 -05:00
parent 9eb20cb668
commit 47454554e3
15 changed files with 165 additions and 169 deletions

View File

@ -127,6 +127,7 @@ public class FhirContext {
private volatile Boolean myFormatJsonSupported; private volatile Boolean myFormatJsonSupported;
private volatile Boolean myFormatNDJsonSupported; private volatile Boolean myFormatNDJsonSupported;
private volatile Boolean myFormatRdfSupported; private volatile Boolean myFormatRdfSupported;
private IFhirValidatorFactory myFhirValidatorFactory = fhirContext -> new FhirValidator(fhirContext);
/** /**
* @deprecated It is recommended that you use one of the static initializer methods instead * @deprecated It is recommended that you use one of the static initializer methods instead
@ -908,7 +909,7 @@ public class FhirContext {
* </p> * </p>
*/ */
public FhirValidator newValidator() { public FhirValidator newValidator() {
return new FhirValidator(this); return myFhirValidatorFactory.newFhirValidator(this);
} }
public ViewGenerator newViewGenerator() { public ViewGenerator newViewGenerator() {
@ -1072,9 +1073,22 @@ public class FhirContext {
* *
* @param theParserErrorHandler The error handler * @param theParserErrorHandler The error handler
*/ */
public void setParserErrorHandler(final IParserErrorHandler theParserErrorHandler) { public FhirContext setParserErrorHandler(final IParserErrorHandler theParserErrorHandler) {
Validate.notNull(theParserErrorHandler, "theParserErrorHandler must not be null"); Validate.notNull(theParserErrorHandler, "theParserErrorHandler must not be null");
myParserErrorHandler = theParserErrorHandler; myParserErrorHandler = theParserErrorHandler;
return this;
}
/**
* Set the factory method used to create FhirValidator instances
*
* @param theFhirValidatorFactory
* @return this
* @since 5.6.0
*/
public FhirContext setFhirValidatorFactory(IFhirValidatorFactory theFhirValidatorFactory) {
myFhirValidatorFactory = theFhirValidatorFactory;
return this;
} }
@SuppressWarnings({"cast"}) @SuppressWarnings({"cast"})

View File

@ -0,0 +1,7 @@
package ca.uhn.fhir.context;
import ca.uhn.fhir.validation.FhirValidator;
public interface IFhirValidatorFactory {
FhirValidator newFhirValidator(FhirContext theFhirContext);
}

View File

@ -58,11 +58,16 @@ public class FhirValidator {
private static final Logger ourLog = LoggerFactory.getLogger(FhirValidator.class); private static final Logger ourLog = LoggerFactory.getLogger(FhirValidator.class);
private static final String I18N_KEY_NO_PH_ERROR = FhirValidator.class.getName() + ".noPhError"; private static final String I18N_KEY_NO_PH_ERROR = FhirValidator.class.getName() + ".noPhError";
public static final int DEFAULT_BUNDLE_VALIDATION_THREADCOUNT = 1;
private static volatile Boolean ourPhPresentOnClasspath; private static volatile Boolean ourPhPresentOnClasspath;
private final FhirContext myContext; private final FhirContext myContext;
private List<IValidatorModule> myValidators = new ArrayList<>(); private List<IValidatorModule> myValidators = new ArrayList<>();
private IInterceptorBroadcaster myInterceptorBraodcaster; private IInterceptorBroadcaster myInterceptorBraodcaster;
// FIXME KHS make it clear in the docs that bundle structure is not validated when this is true
private boolean myConcurrentBundleValidation;
private int myBundleValidationThreadCount = DEFAULT_BUNDLE_VALIDATION_THREADCOUNT;
private ExecutorService myExecutor; private ExecutorService myExecutor;
/** /**
@ -226,7 +231,7 @@ public class FhirValidator {
applyDefaultValidators(); applyDefaultValidators();
if (theResource instanceof IBaseBundle && theOptions.isConcurrentBundleValidation()) { if (theResource instanceof IBaseBundle && myConcurrentBundleValidation) {
return validateBundleEntriesConcurrently((IBaseBundle) theResource, theOptions); return validateBundleEntriesConcurrently((IBaseBundle) theResource, theOptions);
} }
@ -236,7 +241,7 @@ public class FhirValidator {
private ValidationResult validateBundleEntriesConcurrently(IBaseBundle theBundle, ValidationOptions theOptions) { private ValidationResult validateBundleEntriesConcurrently(IBaseBundle theBundle, ValidationOptions theOptions) {
List<IBaseResource> entries = BundleUtil.toListOfResources(myContext, theBundle); List<IBaseResource> entries = BundleUtil.toListOfResources(myContext, theBundle);
ExecutorService executorService = getExecutorService(theOptions); ExecutorService executorService = getExecutorService();
List<Future<ValidationResult>> futures = new ArrayList<>(); List<Future<ValidationResult>> futures = new ArrayList<>();
for (IBaseResource entry : entries) { for (IBaseResource entry : entries) {
futures.add(executorService.submit(() -> validateResource(entry, theOptions))); futures.add(executorService.submit(() -> validateResource(entry, theOptions)));
@ -255,9 +260,9 @@ public class FhirValidator {
return new ValidationResult(myContext, validationMessages.stream().collect(Collectors.toList())); return new ValidationResult(myContext, validationMessages.stream().collect(Collectors.toList()));
} }
private ExecutorService getExecutorService(ValidationOptions theOptions) { private ExecutorService getExecutorService() {
if (myExecutor == null) { if (myExecutor == null) {
int size = theOptions.getBundleValidationThreadCount(); int size = myBundleValidationThreadCount;
ourLog.info("Creating FhirValidation thread pool with size {}", size); ourLog.info("Creating FhirValidation thread pool with size {}", size);
myExecutor = Executors.newFixedThreadPool(size); myExecutor = Executors.newFixedThreadPool(size);
} }
@ -308,7 +313,7 @@ public class FhirValidator {
IValidationContext<IBaseResource> ctx = ValidationContext.forText(myContext, theResource, theOptions); IValidationContext<IBaseResource> ctx = ValidationContext.forText(myContext, theResource, theOptions);
if (ctx.getResource() instanceof IBaseBundle && theOptions.isConcurrentBundleValidation()) { if (ctx.getResource() instanceof IBaseBundle && myConcurrentBundleValidation) {
return validateBundleEntriesConcurrently((IBaseBundle) ctx.getResource(), theOptions); return validateBundleEntriesConcurrently((IBaseBundle) ctx.getResource(), theOptions);
} }
@ -335,4 +340,39 @@ public class FhirValidator {
myExecutor = theExecutor; myExecutor = theExecutor;
return this; return this;
} }
/**
* If this is true, bundles will be validated in parallel threads. The bundle structure itself will not be validated,
* only the resources in its entries.
*/
public boolean isConcurrentBundleValidation() {
return myConcurrentBundleValidation;
}
/**
* If this is true, bundles will be validated in parallel threads. The bundle structure itself will not be validated,
* only the resources in its entries.
*/
public FhirValidator setConcurrentBundleValidation(boolean theConcurrentBundleValidation) {
myConcurrentBundleValidation = theConcurrentBundleValidation;
return this;
}
/**
* The number of threads bundle entries will be validated within. This is only used when
* {@link #isConcurrentBundleValidation} is true.
*/
public int getBundleValidationThreadCount() {
return myBundleValidationThreadCount;
}
/**
* The number of threads bundle entries will be validated within. This is only used when
* {@link #isConcurrentBundleValidation} is true.
*/
public FhirValidator setBundleValidationThreadCount(int theBundleValidationThreadCount) {
myBundleValidationThreadCount = theBundleValidationThreadCount;
return this;
}
} }

View File

@ -30,13 +30,11 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
public class ValidationOptions { public class ValidationOptions {
public static final int DEFAULT_BUNDLE_VALIDATION_THREADCOUNT = 1;
private static ValidationOptions ourEmpty; private static ValidationOptions ourEmpty;
private Set<String> myProfiles; private Set<String> myProfiles;
// FIXME KHS make it clear in the docs that bundle structure is not validated when this is true public ValidationOptions() {
private boolean myConcurrentBundleValidation; }
private int myBundleValidationThreadCount = DEFAULT_BUNDLE_VALIDATION_THREADCOUNT;
public Set<String> getProfiles() { public Set<String> getProfiles() {
return myProfiles != null ? Collections.unmodifiableSet(myProfiles) : Collections.emptySet(); return myProfiles != null ? Collections.unmodifiableSet(myProfiles) : Collections.emptySet();
@ -59,41 +57,6 @@ public class ValidationOptions {
return this; return this;
} }
/**
* If this is true, bundles will be validated in parallel threads. The bundle structure itself will not be validated,
* only the resources in its entries.
*/
public boolean isConcurrentBundleValidation() {
return myConcurrentBundleValidation;
}
/**
* If this is true, bundles will be validated in parallel threads. The bundle structure itself will not be validated,
* only the resources in its entries.
*/
public ValidationOptions setConcurrentBundleValidation(boolean theConcurrentBundleValidation) {
myConcurrentBundleValidation = theConcurrentBundleValidation;
return this;
}
/**
* The number of threads bundle entries will be validated within. This is only used when
* {@link #isConcurrentBundleValidation} is true.
*/
public int getBundleValidationThreadCount() {
return myBundleValidationThreadCount;
}
/**
* The number of threads bundle entries will be validated within. This is only used when
* {@link #isConcurrentBundleValidation} is true.
*/
public ValidationOptions setBundleValidationThreadCount(int theBundleValidationThreadCount) {
myBundleValidationThreadCount = theBundleValidationThreadCount;
return this;
}
public static ValidationOptions empty() { public static ValidationOptions empty() {
ValidationOptions retVal = ourEmpty; ValidationOptions retVal = ourEmpty;
if (retVal == null) { if (retVal == null) {

View File

@ -86,7 +86,6 @@ import ca.uhn.fhir.rest.server.IRestfulServerDefaults;
import ca.uhn.fhir.rest.server.RestfulServerUtils; import ca.uhn.fhir.rest.server.RestfulServerUtils;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException; import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException;
import ca.uhn.fhir.rest.server.exceptions.NotImplementedOperationException;
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException; import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException; import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
@ -1776,7 +1775,6 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
} }
FhirValidator validator = getContext().newValidator(); FhirValidator validator = getContext().newValidator();
validator.setInterceptorBroadcaster(CompositeInterceptorBroadcaster.newCompositeBroadcaster(myInterceptorBroadcaster, theRequest)); validator.setInterceptorBroadcaster(CompositeInterceptorBroadcaster.newCompositeBroadcaster(myInterceptorBroadcaster, theRequest));
validator.registerValidatorModule(getInstanceValidator()); validator.registerValidatorModule(getInstanceValidator());
validator.registerValidatorModule(new IdChecker(theMode)); validator.registerValidatorModule(new IdChecker(theMode));

View File

@ -16,7 +16,6 @@ import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.param.TokenParamModifier; import ca.uhn.fhir.rest.param.TokenParamModifier;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException; import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.validation.FhirValidator; import ca.uhn.fhir.validation.FhirValidator;

View File

@ -60,7 +60,6 @@ import ca.uhn.fhir.jpa.entity.TermValueSetConcept;
import ca.uhn.fhir.jpa.interceptor.PerformanceTracingLoggingInterceptor; import ca.uhn.fhir.jpa.interceptor.PerformanceTracingLoggingInterceptor;
import ca.uhn.fhir.jpa.model.config.PartitionSettings; import ca.uhn.fhir.jpa.model.config.PartitionSettings;
import ca.uhn.fhir.jpa.model.entity.ModelConfig; import ca.uhn.fhir.jpa.model.entity.ModelConfig;
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.packages.IPackageInstallerSvc; import ca.uhn.fhir.jpa.packages.IPackageInstallerSvc;
import ca.uhn.fhir.jpa.partition.IPartitionLookupSvc; import ca.uhn.fhir.jpa.partition.IPartitionLookupSvc;
import ca.uhn.fhir.jpa.provider.r4.JpaSystemProviderR4; import ca.uhn.fhir.jpa.provider.r4.JpaSystemProviderR4;
@ -93,8 +92,6 @@ import ca.uhn.fhir.util.ClasspathUtil;
import ca.uhn.fhir.util.UrlUtil; import ca.uhn.fhir.util.UrlUtil;
import ca.uhn.fhir.validation.FhirValidator; import ca.uhn.fhir.validation.FhirValidator;
import ca.uhn.fhir.validation.ValidationResult; import ca.uhn.fhir.validation.ValidationResult;
import org.hibernate.search.mapper.orm.Search;
import org.hibernate.search.mapper.orm.session.SearchSession;
import org.hl7.fhir.common.hapi.validation.support.CachingValidationSupport; import org.hl7.fhir.common.hapi.validation.support.CachingValidationSupport;
import org.hl7.fhir.common.hapi.validation.validator.FhirInstanceValidator; import org.hl7.fhir.common.hapi.validation.validator.FhirInstanceValidator;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;

View File

@ -15,7 +15,6 @@ import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.param.TokenParamModifier; import ca.uhn.fhir.rest.param.TokenParamModifier;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException; import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.validation.FhirValidator; import ca.uhn.fhir.validation.FhirValidator;

View File

@ -49,7 +49,6 @@ import ca.uhn.fhir.jpa.entity.TermValueSet;
import ca.uhn.fhir.jpa.entity.TermValueSetConcept; import ca.uhn.fhir.jpa.entity.TermValueSetConcept;
import ca.uhn.fhir.jpa.interceptor.PerformanceTracingLoggingInterceptor; import ca.uhn.fhir.jpa.interceptor.PerformanceTracingLoggingInterceptor;
import ca.uhn.fhir.jpa.model.entity.ModelConfig; import ca.uhn.fhir.jpa.model.entity.ModelConfig;
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.provider.r5.JpaSystemProviderR5; import ca.uhn.fhir.jpa.provider.r5.JpaSystemProviderR5;
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider; import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
import ca.uhn.fhir.jpa.search.IStaleSearchDeletingSvc; import ca.uhn.fhir.jpa.search.IStaleSearchDeletingSvc;
@ -76,8 +75,6 @@ import ca.uhn.fhir.util.UrlUtil;
import ca.uhn.fhir.validation.FhirValidator; import ca.uhn.fhir.validation.FhirValidator;
import ca.uhn.fhir.validation.ValidationResult; import ca.uhn.fhir.validation.ValidationResult;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.hibernate.search.mapper.orm.Search;
import org.hibernate.search.mapper.orm.session.SearchSession;
import org.hl7.fhir.common.hapi.validation.validator.FhirInstanceValidator; import org.hl7.fhir.common.hapi.validation.validator.FhirInstanceValidator;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;

View File

@ -32,7 +32,6 @@ import ca.uhn.fhir.validation.FhirValidator;
import ca.uhn.fhir.validation.IValidatorModule; import ca.uhn.fhir.validation.IValidatorModule;
import ca.uhn.fhir.validation.ResultSeverityEnum; import ca.uhn.fhir.validation.ResultSeverityEnum;
import ca.uhn.fhir.validation.SingleValidationMessage; import ca.uhn.fhir.validation.SingleValidationMessage;
import ca.uhn.fhir.validation.ValidationOptions;
import ca.uhn.fhir.validation.ValidationResult; import ca.uhn.fhir.validation.ValidationResult;
import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.text.StrLookup; import org.apache.commons.lang3.text.StrLookup;
@ -76,7 +75,6 @@ public abstract class BaseValidatingInterceptor<T> extends ValidationResultEnric
private List<IValidatorModule> myValidatorModules; private List<IValidatorModule> myValidatorModules;
private FhirValidator myValidator; private FhirValidator myValidator;
private final ValidationOptions myValidationOptions = new ValidationOptions();
private void addResponseIssueHeader(RequestDetails theRequestDetails, SingleValidationMessage theNext) { private void addResponseIssueHeader(RequestDetails theRequestDetails, SingleValidationMessage theNext) {
// Perform any string substitutions from the message format // Perform any string substitutions from the message format
@ -117,7 +115,7 @@ public abstract class BaseValidatingInterceptor<T> extends ValidationResultEnric
} }
abstract ValidationResult doValidate(FhirValidator theValidator, T theRequest, ValidationOptions theValidationOptions); abstract ValidationResult doValidate(FhirValidator theValidator, T theRequest);
/** /**
* Fail the request by throwing an {@link UnprocessableEntityException} as a result of a validation failure. * Fail the request by throwing an {@link UnprocessableEntityException} as a result of a validation failure.
@ -312,21 +310,22 @@ public abstract class BaseValidatingInterceptor<T> extends ValidationResultEnric
return null; return null;
} }
FhirValidator validator; FhirValidator fhirValidator;
if (myValidator != null) { if (myValidator != null) {
validator = myValidator; fhirValidator = myValidator;
} else { } else {
validator = theRequestDetails.getServer().getFhirContext().newValidator(); // FIXME KHS this is our validator
fhirValidator = theRequestDetails.getServer().getFhirContext().newValidator();
if (myValidatorModules != null) { if (myValidatorModules != null) {
for (IValidatorModule next : myValidatorModules) { for (IValidatorModule next : myValidatorModules) {
validator.registerValidatorModule(next); fhirValidator.registerValidatorModule(next);
} }
} }
} }
ValidationResult validationResult; ValidationResult validationResult;
try { try {
validationResult = doValidate(validator, theRequest, myValidationOptions); validationResult = doValidate(fhirValidator, theRequest);
} catch (Exception e) { } catch (Exception e) {
if (myIgnoreValidatorExceptions) { if (myIgnoreValidatorExceptions) {
ourLog.warn("Validator threw an exception during validation", e); ourLog.warn("Validator threw an exception during validation", e);
@ -392,14 +391,6 @@ public abstract class BaseValidatingInterceptor<T> extends ValidationResultEnric
return validationResult; return validationResult;
} }
protected void setConcurrentBundleValidation(boolean theConcurrentBundleValidation) {
myValidationOptions.setConcurrentBundleValidation(theConcurrentBundleValidation);
}
protected void setBundleValidationThreadCount(int theBundleValidationThreadCount) {
myValidationOptions.setBundleValidationThreadCount(theBundleValidationThreadCount);
}
private static class MyLookup extends StrLookup<String> { private static class MyLookup extends StrLookup<String> {
private SingleValidationMessage myMessage; private SingleValidationMessage myMessage;

View File

@ -30,7 +30,6 @@ import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.rest.server.method.ResourceParameter; import ca.uhn.fhir.rest.server.method.ResourceParameter;
import ca.uhn.fhir.validation.FhirValidator; import ca.uhn.fhir.validation.FhirValidator;
import ca.uhn.fhir.validation.ResultSeverityEnum; import ca.uhn.fhir.validation.ResultSeverityEnum;
import ca.uhn.fhir.validation.ValidationOptions;
import ca.uhn.fhir.validation.ValidationResult; import ca.uhn.fhir.validation.ValidationResult;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@ -54,8 +53,8 @@ public class RequestValidatingInterceptor extends BaseValidatingInterceptor<Stri
private boolean myAddValidationResultsToResponseOperationOutcome = true; private boolean myAddValidationResultsToResponseOperationOutcome = true;
@Override @Override
ValidationResult doValidate(FhirValidator theValidator, String theRequest, ValidationOptions theValidationOptions) { ValidationResult doValidate(FhirValidator theValidator, String theRequest) {
return theValidator.validateWithResult(theRequest, theValidationOptions); return theValidator.validateWithResult(theRequest);
} }
@Hook(Pointcut.SERVER_INCOMING_REQUEST_POST_PROCESSED) @Hook(Pointcut.SERVER_INCOMING_REQUEST_POST_PROCESSED)

View File

@ -27,7 +27,6 @@ import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException; import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.validation.FhirValidator; import ca.uhn.fhir.validation.FhirValidator;
import ca.uhn.fhir.validation.ResultSeverityEnum; import ca.uhn.fhir.validation.ResultSeverityEnum;
import ca.uhn.fhir.validation.ValidationOptions;
import ca.uhn.fhir.validation.ValidationResult; import ca.uhn.fhir.validation.ValidationResult;
import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
@ -62,8 +61,8 @@ public class ResponseValidatingInterceptor extends BaseValidatingInterceptor<IBa
} }
@Override @Override
ValidationResult doValidate(FhirValidator theValidator, IBaseResource theRequest, ValidationOptions theValidationOptions) { ValidationResult doValidate(FhirValidator theValidator, IBaseResource theRequest) {
return theValidator.validateWithResult(theRequest, theValidationOptions); return theValidator.validateWithResult(theRequest);
} }
@Hook(Pointcut.SERVER_OUTGOING_RESPONSE) @Hook(Pointcut.SERVER_OUTGOING_RESPONSE)

View File

@ -6,7 +6,7 @@ import ca.uhn.fhir.jpa.model.entity.ModelConfig;
import ca.uhn.fhir.jpa.model.entity.ResourceEncodingEnum; import ca.uhn.fhir.jpa.model.entity.ResourceEncodingEnum;
import ca.uhn.fhir.rest.api.SearchTotalModeEnum; import ca.uhn.fhir.rest.api.SearchTotalModeEnum;
import ca.uhn.fhir.util.HapiExtensions; import ca.uhn.fhir.util.HapiExtensions;
import ca.uhn.fhir.validation.ValidationOptions; import ca.uhn.fhir.validation.FhirValidator;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@ -280,13 +280,13 @@ public class DaoConfig {
private boolean myAdvancedLuceneIndexing = false; private boolean myAdvancedLuceneIndexing = false;
/** /**
* @see ValidationOptions#getBundleValidationThreadCount() * @see FhirValidator#getBundleValidationThreadCount()
* @since 5.6.0 * @since 5.6.0
*/ */
private int myBundleValidationThreadCount = ValidationOptions.DEFAULT_BUNDLE_VALIDATION_THREADCOUNT; private int myBundleValidationThreadCount = FhirValidator.DEFAULT_BUNDLE_VALIDATION_THREADCOUNT;
/** /**
* @see ValidationOptions#isConcurrentBundleValidation() * @see FhirValidator#isConcurrentBundleValidation()
* @since 5.6.0 * @since 5.6.0
*/ */
private boolean myConcurrentBundleValidation; private boolean myConcurrentBundleValidation;
@ -2686,7 +2686,7 @@ public class DaoConfig {
} }
/** /**
* @see ValidationOptions#getBundleValidationThreadCount() * @see FhirValidator#getBundleValidationThreadCount()
* @since 5.6.0 * @since 5.6.0
*/ */
public int getBundleValidationThreadCount() { public int getBundleValidationThreadCount() {
@ -2694,7 +2694,7 @@ public class DaoConfig {
} }
/** /**
* @see ValidationOptions#getBundleValidationThreadCount() * @see FhirValidator#getBundleValidationThreadCount()
* @since 5.6.0 * @since 5.6.0
*/ */
public DaoConfig setBundleValidationThreadCount(int theBundleValidationThreadCount) { public DaoConfig setBundleValidationThreadCount(int theBundleValidationThreadCount) {
@ -2703,7 +2703,7 @@ public class DaoConfig {
} }
/** /**
* @see ValidationOptions#isConcurrentBundleValidation() * @see FhirValidator#isConcurrentBundleValidation()
* @since 5.6.0 * @since 5.6.0
*/ */
public boolean isConcurrentBundleValidation() { public boolean isConcurrentBundleValidation() {
@ -2711,7 +2711,7 @@ public class DaoConfig {
} }
/** /**
* @see ValidationOptions#isConcurrentBundleValidation() * @see FhirValidator#isConcurrentBundleValidation()
* @since 5.6.0 * @since 5.6.0
*/ */
public DaoConfig setConcurrentBundleValidation(boolean theConcurrentBundleValidation) { public DaoConfig setConcurrentBundleValidation(boolean theConcurrentBundleValidation) {

View File

@ -15,7 +15,6 @@ import ca.uhn.fhir.util.TestUtil;
import ca.uhn.fhir.validation.FhirValidator; import ca.uhn.fhir.validation.FhirValidator;
import ca.uhn.fhir.validation.ResultSeverityEnum; import ca.uhn.fhir.validation.ResultSeverityEnum;
import ca.uhn.fhir.validation.SingleValidationMessage; import ca.uhn.fhir.validation.SingleValidationMessage;
import ca.uhn.fhir.validation.ValidationOptions;
import ca.uhn.fhir.validation.ValidationResult; import ca.uhn.fhir.validation.ValidationResult;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
@ -66,7 +65,6 @@ import org.hl7.fhir.r4.utils.FHIRPathEngine;
import org.hl7.fhir.r5.utils.IResourceValidator; import org.hl7.fhir.r5.utils.IResourceValidator;
import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.hl7.fhir.utilities.xhtml.XhtmlNode; import org.hl7.fhir.utilities.xhtml.XhtmlNode;
import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Disabled;
@ -114,7 +112,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
public LoggingExtension myLoggingExtension = new LoggingExtension(); public LoggingExtension myLoggingExtension = new LoggingExtension();
private FhirInstanceValidator myInstanceVal; private FhirInstanceValidator myInstanceVal;
private Map<String, ValueSetExpansionComponent> mySupportedCodeSystemsForExpansion; private Map<String, ValueSetExpansionComponent> mySupportedCodeSystemsForExpansion;
private FhirValidator myVal; private FhirValidator myFhirValidator;
private ArrayList<String> myValidConcepts; private ArrayList<String> myValidConcepts;
private Set<String> myValidSystems = new HashSet<>(); private Set<String> myValidSystems = new HashSet<>();
private Map<String, StructureDefinition> myStructureDefinitionMap = new HashMap<>(); private Map<String, StructureDefinition> myStructureDefinitionMap = new HashMap<>();
@ -136,7 +134,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
resource.setSubject(new Reference("#invalid-ref")); resource.setSubject(new Reference("#invalid-ref"));
ValidationResult output = myVal.validateWithResult(resource); ValidationResult output = myFhirValidator.validateWithResult(resource);
List<SingleValidationMessage> nonInfo = logResultsAndReturnNonInformationalOnes(output); List<SingleValidationMessage> nonInfo = logResultsAndReturnNonInformationalOnes(output);
assertThat(nonInfo, hasSize(2)); assertThat(nonInfo, hasSize(2));
} }
@ -144,21 +142,20 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@BeforeEach @BeforeEach
public void before() { public void before() {
myVal = ourCtx.newValidator(); myFhirValidator = ourCtx.newValidator();
myVal.setValidateAgainstStandardSchema(false); myFhirValidator.setValidateAgainstStandardSchema(false);
myVal.setValidateAgainstStandardSchematron(false); myFhirValidator.setValidateAgainstStandardSchematron(false);
// This is only used if the validation is performed with validationOptions.isConcurrentBundleValidation = true // This is only used if the validation is performed with validationOptions.isConcurrentBundleValidation = true
myVal.setExecutor(Executors.newFixedThreadPool(4)); myFhirValidator.setExecutor(Executors.newFixedThreadPool(4));
IValidationSupport mockSupport = mock(IValidationSupport.class); IValidationSupport mockSupport = mock(IValidationSupport.class);
when(mockSupport.getFhirContext()).thenReturn(ourCtx); when(mockSupport.getFhirContext()).thenReturn(ourCtx);
ValidationSupportChain chain = new ValidationSupportChain(myDefaultValidationSupport, mockSupport, new InMemoryTerminologyServerValidationSupport(ourCtx), new CommonCodeSystemsTerminologyService(ourCtx), new SnapshotGeneratingValidationSupport(ourCtx)); ValidationSupportChain chain = new ValidationSupportChain(myDefaultValidationSupport, mockSupport, new InMemoryTerminologyServerValidationSupport(ourCtx), new CommonCodeSystemsTerminologyService(ourCtx), new SnapshotGeneratingValidationSupport(ourCtx));
myValidationSupport = new CachingValidationSupport(chain); myValidationSupport = new CachingValidationSupport(chain);
ourCtx.setValidationSupport(myValidationSupport);
myInstanceVal = new FhirInstanceValidator(myValidationSupport); myInstanceVal = new FhirInstanceValidator(myValidationSupport);
myVal.registerValidatorModule(myInstanceVal); myFhirValidator.registerValidatorModule(myInstanceVal);
mySupportedCodeSystemsForExpansion = new HashMap<>(); mySupportedCodeSystemsForExpansion = new HashMap<>();
@ -530,7 +527,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
ourLog.info("Encoded: {}", encoded); ourLog.info("Encoded: {}", encoded);
ValidationResult output = myVal.validateWithResult(encoded); ValidationResult output = myFhirValidator.validateWithResult(encoded);
List<SingleValidationMessage> errors = logResultsAndReturnNonInformationalOnes(output); List<SingleValidationMessage> errors = logResultsAndReturnNonInformationalOnes(output);
assertEquals(1, errors.size()); assertEquals(1, errors.size());
assertEquals("The value '%%%2@()()' is not a valid Base64 value", errors.get(0).getMessage()); assertEquals("The value '%%%2@()()' is not a valid Base64 value", errors.get(0).getMessage());
@ -541,7 +538,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
public void testValidateBundleWithNoFullUrl() throws IOException { public void testValidateBundleWithNoFullUrl() throws IOException {
String encoded = loadResource("/r4/r4-caredove-bundle.json"); String encoded = loadResource("/r4/r4-caredove-bundle.json");
ValidationResult output = myVal.validateWithResult(encoded); ValidationResult output = myFhirValidator.validateWithResult(encoded);
List<SingleValidationMessage> errors = logResultsAndReturnNonInformationalOnes(output); List<SingleValidationMessage> errors = logResultsAndReturnNonInformationalOnes(output);
errors = errors errors = errors
.stream() .stream()
@ -563,7 +560,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
ourLog.info("Encoded: {}", encoded); ourLog.info("Encoded: {}", encoded);
ValidationResult output = myVal.validateWithResult(encoded); ValidationResult output = myFhirValidator.validateWithResult(encoded);
List<SingleValidationMessage> errors = logResultsAndReturnNonInformationalOnes(output); List<SingleValidationMessage> errors = logResultsAndReturnNonInformationalOnes(output);
assertEquals(0, errors.size()); assertEquals(0, errors.size());
@ -607,7 +604,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
t.setSystem(org.hl7.fhir.r4.model.ContactPoint.ContactPointSystem.URL); t.setSystem(org.hl7.fhir.r4.model.ContactPoint.ContactPointSystem.URL);
t.setValue("http://infoway-inforoute.ca"); t.setValue("http://infoway-inforoute.ca");
ValidationResult results = myVal.validateWithResult(p); ValidationResult results = myFhirValidator.validateWithResult(p);
List<SingleValidationMessage> outcome = logResultsAndReturnNonInformationalOnes(results); List<SingleValidationMessage> outcome = logResultsAndReturnNonInformationalOnes(results);
assertThat(outcome, empty()); assertThat(outcome, empty());
@ -619,7 +616,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
@Test @Test
public void testExtensionUrlWithHl7Url() throws IOException { public void testExtensionUrlWithHl7Url() throws IOException {
String input = IOUtils.toString(FhirInstanceValidator.class.getResourceAsStream("/bug872-ext-with-hl7-url.json"), Charsets.UTF_8); String input = IOUtils.toString(FhirInstanceValidator.class.getResourceAsStream("/bug872-ext-with-hl7-url.json"), Charsets.UTF_8);
ValidationResult output = myVal.validateWithResult(input); ValidationResult output = myFhirValidator.validateWithResult(input);
List<SingleValidationMessage> nonInfo = logResultsAndReturnNonInformationalOnes(output); List<SingleValidationMessage> nonInfo = logResultsAndReturnNonInformationalOnes(output);
assertThat(nonInfo, empty()); assertThat(nonInfo, empty());
} }
@ -634,7 +631,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
@Test @Test
public void testLargeBase64() throws IOException { public void testLargeBase64() throws IOException {
String input = IOUtils.toString(FhirInstanceValidatorR4Test.class.getResourceAsStream("/r4/diagnosticreport-example-gingival-mass.json"), Constants.CHARSET_UTF8); String input = IOUtils.toString(FhirInstanceValidatorR4Test.class.getResourceAsStream("/r4/diagnosticreport-example-gingival-mass.json"), Constants.CHARSET_UTF8);
ValidationResult output = myVal.validateWithResult(input); ValidationResult output = myFhirValidator.validateWithResult(input);
List<SingleValidationMessage> errors = logResultsAndReturnAll(output); List<SingleValidationMessage> errors = logResultsAndReturnAll(output);
assertEquals(1, errors.size()); assertEquals(1, errors.size());
assertEquals("None of the codings provided are in the value set http://hl7.org/fhir/ValueSet/report-codes (http://hl7.org/fhir/ValueSet/report-codes), and a coding is recommended to come from this value set) (codes = http://loinc.org#1-8)", errors.get(0).getMessage()); assertEquals("None of the codings provided are in the value set http://hl7.org/fhir/ValueSet/report-codes (http://hl7.org/fhir/ValueSet/report-codes), and a coding is recommended to come from this value set) (codes = http://loinc.org#1-8)", errors.get(0).getMessage());
@ -650,7 +647,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
int passes = 1; int passes = 1;
for (int i = 0; i < passes; i++) { for (int i = 0; i < passes; i++) {
ourLog.info("Pass {}", i + 1); ourLog.info("Pass {}", i + 1);
output = myVal.validateWithResult(input); output = myFhirValidator.validateWithResult(input);
} }
long delay = System.currentTimeMillis() - start; long delay = System.currentTimeMillis() - start;
@ -687,7 +684,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
ourLog.info("Validating {}", next.getId()); ourLog.info("Validating {}", next.getId());
ourLog.trace(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(next)); ourLog.trace(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(next));
ValidationResult output = myVal.validateWithResult(next); ValidationResult output = myFhirValidator.validateWithResult(next);
List<SingleValidationMessage> results = logResultsAndReturnAll(output); List<SingleValidationMessage> results = logResultsAndReturnAll(output);
// This isn't a validator problem but a definition problem.. it should get fixed at some point and // This isn't a validator problem but a definition problem.. it should get fixed at some point and
@ -715,7 +712,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
public void testValidateBundleWithNoType() throws Exception { public void testValidateBundleWithNoType() throws Exception {
String vsContents = loadResource("/r4/bundle-with-no-type.json"); String vsContents = loadResource("/r4/bundle-with-no-type.json");
ValidationResult output = myVal.validateWithResult(vsContents); ValidationResult output = myFhirValidator.validateWithResult(vsContents);
logResultsAndReturnNonInformationalOnes(output); logResultsAndReturnNonInformationalOnes(output);
assertThat(output.getMessages().toString(), containsString("Bundle.type: minimum required = 1, but only found 0")); assertThat(output.getMessages().toString(), containsString("Bundle.type: minimum required = 1, but only found 0"));
} }
@ -732,7 +729,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
"\"name\":[ {\"family\":\"bar\"} ]" + "\"name\":[ {\"family\":\"bar\"} ]" +
"}"; "}";
ValidationResult output = myVal.validateWithResult(patient); ValidationResult output = myFhirValidator.validateWithResult(patient);
logResultsAndReturnNonInformationalOnes(output); logResultsAndReturnNonInformationalOnes(output);
assertThat(output.getMessages().toString(), containsString("Error parsing JSON source: Duplicated property name")); assertThat(output.getMessages().toString(), containsString("Error parsing JSON source: Duplicated property name"));
} }
@ -760,7 +757,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
// bool = (BooleanType) fpOutput.get(0); // bool = (BooleanType) fpOutput.get(0);
// assertTrue(bool.getValue()); // assertTrue(bool.getValue());
ValidationResult output = myVal.validateWithResult(inputString); ValidationResult output = myFhirValidator.validateWithResult(inputString);
List<SingleValidationMessage> errors = logResultsAndReturnNonInformationalOnes(output); List<SingleValidationMessage> errors = logResultsAndReturnNonInformationalOnes(output);
assertThat(errors, empty()); assertThat(errors, empty());
@ -771,7 +768,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
public void testValidateDocument() throws Exception { public void testValidateDocument() throws Exception {
String vsContents = loadResource("/sample-document.xml"); String vsContents = loadResource("/sample-document.xml");
ValidationResult output = myVal.validateWithResult(vsContents); ValidationResult output = myFhirValidator.validateWithResult(vsContents);
logResultsAndReturnNonInformationalOnes(output); logResultsAndReturnNonInformationalOnes(output);
assertTrue(output.isSuccessful()); assertTrue(output.isSuccessful());
} }
@ -823,7 +820,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
public void testValidateQuestionnaireResponse() throws IOException { public void testValidateQuestionnaireResponse() throws IOException {
String input = loadResource("/qr_jon.xml"); String input = loadResource("/qr_jon.xml");
ValidationResult output = myVal.validateWithResult(input); ValidationResult output = myFhirValidator.validateWithResult(input);
logResultsAndReturnAll(output); logResultsAndReturnAll(output);
assertThat(output.getMessages().toString(), containsString("Items not of type group should not have items - Item with linkId 5.1 of type BOOLEAN has 1 item(s)")); assertThat(output.getMessages().toString(), containsString("Items not of type group should not have items - Item with linkId 5.1 of type BOOLEAN has 1 item(s)"));
@ -840,7 +837,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
" \"id\":\"123\"" + " \"id\":\"123\"" +
"}"; "}";
ValidationResult output = myVal.validateWithResult(input); ValidationResult output = myFhirValidator.validateWithResult(input);
assertEquals(0, output.getMessages().size(), output.toString()); assertEquals(0, output.getMessages().size(), output.toString());
} }
@ -857,7 +854,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
"\"foo\":\"123\"" + "\"foo\":\"123\"" +
"}"; "}";
ValidationResult output = myVal.validateWithResult(input); ValidationResult output = myFhirValidator.validateWithResult(input);
assertEquals(1, output.getMessages().size(), output.toString()); assertEquals(1, output.getMessages().size(), output.toString());
ourLog.info(output.getMessages().get(0).getLocationString()); ourLog.info(output.getMessages().get(0).getLocationString());
ourLog.info(output.getMessages().get(0).getMessage()); ourLog.info(output.getMessages().get(0).getMessage());
@ -876,7 +873,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
public void testValidateRawJsonResourceFromExamples() throws Exception { public void testValidateRawJsonResourceFromExamples() throws Exception {
String input = loadResource("/testscript-search.json"); String input = loadResource("/testscript-search.json");
ValidationResult output = myVal.validateWithResult(input); ValidationResult output = myFhirValidator.validateWithResult(input);
logResultsAndReturnNonInformationalOnes(output); logResultsAndReturnNonInformationalOnes(output);
// assertEquals(output.toString(), 1, output.getMessages().size()); // assertEquals(output.toString(), 1, output.getMessages().size());
// ourLog.info(output.getMessages().get(0).getLocationString()); // ourLog.info(output.getMessages().get(0).getLocationString());
@ -912,7 +909,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
* } * }
*/ */
ValidationResult output = myVal.validateWithResult(encoded); ValidationResult output = myFhirValidator.validateWithResult(encoded);
assertEquals(1, output.getMessages().size(), output.toString()); assertEquals(1, output.getMessages().size(), output.toString());
assertEquals("Unknown extension http://hl7.org/fhir/v3/ethnicity", output.getMessages().get(0).getMessage()); assertEquals("Unknown extension http://hl7.org/fhir/v3/ethnicity", output.getMessages().get(0).getMessage());
@ -947,7 +944,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
*/ */
myInstanceVal.setAnyExtensionsAllowed(false); myInstanceVal.setAnyExtensionsAllowed(false);
ValidationResult output = myVal.validateWithResult(encoded); ValidationResult output = myFhirValidator.validateWithResult(encoded);
assertEquals(1, output.getMessages().size(), output.toString()); assertEquals(1, output.getMessages().size(), output.toString());
assertEquals("The extension http://hl7.org/fhir/v3/ethnicity is unknown, and not allowed here", output.getMessages().get(0).getMessage()); assertEquals("The extension http://hl7.org/fhir/v3/ethnicity is unknown, and not allowed here", output.getMessages().get(0).getMessage());
@ -964,7 +961,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
" </text>" + " </text>" +
"</Patient>"; "</Patient>";
ValidationResult output = myVal.validateWithResult(input); ValidationResult output = myFhirValidator.validateWithResult(input);
assertEquals(0, output.getMessages().size(), output.toString()); assertEquals(0, output.getMessages().size(), output.toString());
} }
@ -980,7 +977,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
"<foo value=\"222\"/>" + "<foo value=\"222\"/>" +
"</Patient>"; "</Patient>";
ValidationResult output = myVal.validateWithResult(input); ValidationResult output = myFhirValidator.validateWithResult(input);
assertEquals(1, output.getMessages().size(), output.toString()); assertEquals(1, output.getMessages().size(), output.toString());
ourLog.info(output.getMessages().get(0).getLocationString()); ourLog.info(output.getMessages().get(0).getLocationString());
ourLog.info(output.getMessages().get(0).getMessage()); ourLog.info(output.getMessages().get(0).getMessage());
@ -1000,7 +997,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
"<name><given/></name>" + "<name><given/></name>" +
"</Patient>"; "</Patient>";
ValidationResult output = myVal.validateWithResult(input); ValidationResult output = myFhirValidator.validateWithResult(input);
List<SingleValidationMessage> messages = logResultsAndReturnNonInformationalOnes(output); List<SingleValidationMessage> messages = logResultsAndReturnNonInformationalOnes(output);
assertEquals(3, messages.size(), output.toString()); assertEquals(3, messages.size(), output.toString());
assertThat(messages.get(0).getMessage(), containsString("Element must have some content")); assertThat(messages.get(0).getMessage(), containsString("Element must have some content"));
@ -1035,7 +1032,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
" </timingTiming>\n" + " </timingTiming>\n" +
" </ActivityDefinition>"; " </ActivityDefinition>";
ValidationResult output = myVal.validateWithResult(input); ValidationResult output = myFhirValidator.validateWithResult(input);
List<SingleValidationMessage> res = logResultsAndReturnNonInformationalOnes(output); List<SingleValidationMessage> res = logResultsAndReturnNonInformationalOnes(output);
assertEquals(1, res.size(), output.toString()); assertEquals(1, res.size(), output.toString());
assertEquals("A code with no system has no defined meaning. A system should be provided", output.getMessages().get(0).getMessage()); assertEquals("A code with no system has no defined meaning. A system should be provided", output.getMessages().get(0).getMessage());
@ -1050,7 +1047,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
p.getText().setDiv(new XhtmlNode().setValue("<div>AA</div>")).setStatus(Narrative.NarrativeStatus.GENERATED); p.getText().setDiv(new XhtmlNode().setValue("<div>AA</div>")).setStatus(Narrative.NarrativeStatus.GENERATED);
p.getManagingOrganization().setDisplay("HELLO"); p.getManagingOrganization().setDisplay("HELLO");
ValidationResult output = myVal.validateWithResult(p); ValidationResult output = myFhirValidator.validateWithResult(p);
List<SingleValidationMessage> nonInfo = logResultsAndReturnNonInformationalOnes(output); List<SingleValidationMessage> nonInfo = logResultsAndReturnNonInformationalOnes(output);
assertThat(nonInfo, empty()); assertThat(nonInfo, empty());
} }
@ -1065,7 +1062,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
p.getManagingOrganization().getIdentifier().setSystem("http://acme.org"); p.getManagingOrganization().getIdentifier().setSystem("http://acme.org");
p.getManagingOrganization().getIdentifier().setValue("foo"); p.getManagingOrganization().getIdentifier().setValue("foo");
ValidationResult output = myVal.validateWithResult(p); ValidationResult output = myFhirValidator.validateWithResult(p);
List<SingleValidationMessage> nonInfo = logResultsAndReturnNonInformationalOnes(output); List<SingleValidationMessage> nonInfo = logResultsAndReturnNonInformationalOnes(output);
assertThat(nonInfo, empty()); assertThat(nonInfo, empty());
} }
@ -1085,7 +1082,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
rp.getPatient().setReference("Patient/1"); rp.getPatient().setReference("Patient/1");
rp.addRelationship().addCoding().setSystem("http://terminology.hl7.org/CodeSystem/v2-0131").setCode("C"); rp.addRelationship().addCoding().setSystem("http://terminology.hl7.org/CodeSystem/v2-0131").setCode("C");
ValidationResult results = myVal.validateWithResult(rp); ValidationResult results = myFhirValidator.validateWithResult(rp);
List<SingleValidationMessage> outcome = logResultsAndReturnNonInformationalOnes(results); List<SingleValidationMessage> outcome = logResultsAndReturnNonInformationalOnes(results);
assertThat(outcome, empty()); assertThat(outcome, empty());
@ -1096,7 +1093,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
rp.getPatient().setReference("Patient/1"); rp.getPatient().setReference("Patient/1");
rp.addRelationship().addCoding().setSystem("http://terminology.hl7.org/CodeSystem/v2-0131").setCode("GAGAGAGA"); rp.addRelationship().addCoding().setSystem("http://terminology.hl7.org/CodeSystem/v2-0131").setCode("GAGAGAGA");
results = myVal.validateWithResult(rp); results = myFhirValidator.validateWithResult(rp);
outcome = logResultsAndReturnNonInformationalOnes(results); outcome = logResultsAndReturnNonInformationalOnes(results);
assertThat(outcome, not(empty())); assertThat(outcome, not(empty()));
@ -1115,7 +1112,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
input.getCode().addCoding().setSystem("http://loinc.org").setCode("12345"); input.getCode().addCoding().setSystem("http://loinc.org").setCode("12345");
myInstanceVal.setValidationSupport(myValidationSupport); myInstanceVal.setValidationSupport(myValidationSupport);
ValidationResult output = myVal.validateWithResult(input); ValidationResult output = myFhirValidator.validateWithResult(input);
List<SingleValidationMessage> errors = logResultsAndReturnAll(output); List<SingleValidationMessage> errors = logResultsAndReturnAll(output);
assertEquals(ResultSeverityEnum.ERROR, errors.get(0).getSeverity()); assertEquals(ResultSeverityEnum.ERROR, errors.get(0).getSeverity());
@ -1136,7 +1133,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
input.getCode().addCoding().setSystem("http://loinc.org").setCode("12345"); input.getCode().addCoding().setSystem("http://loinc.org").setCode("12345");
myInstanceVal.setValidationSupport(myValidationSupport); myInstanceVal.setValidationSupport(myValidationSupport);
ValidationResult output = myVal.validateWithResult(input); ValidationResult output = myFhirValidator.validateWithResult(input);
List<SingleValidationMessage> errors = logResultsAndReturnNonInformationalOnes(output); List<SingleValidationMessage> errors = logResultsAndReturnNonInformationalOnes(output);
assertThat(errors.toString(), containsString("Observation.subject: minimum required = 1, but only found 0")); assertThat(errors.toString(), containsString("Observation.subject: minimum required = 1, but only found 0"));
@ -1156,7 +1153,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
input.setStatus(ObservationStatus.FINAL); input.setStatus(ObservationStatus.FINAL);
myInstanceVal.setValidationSupport(myValidationSupport); myInstanceVal.setValidationSupport(myValidationSupport);
ValidationResult output = myVal.validateWithResult(input); ValidationResult output = myFhirValidator.validateWithResult(input);
List<SingleValidationMessage> errors = logResultsAndReturnNonInformationalOnes(output); List<SingleValidationMessage> errors = logResultsAndReturnNonInformationalOnes(output);
assertEquals(1, errors.size()); assertEquals(1, errors.size());
@ -1173,7 +1170,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
input.getCode().addCoding().setSystem("http://loinc.org").setCode("12345"); input.getCode().addCoding().setSystem("http://loinc.org").setCode("12345");
input.setValue(new StringType("AAA")); input.setValue(new StringType("AAA"));
ValidationResult output = myVal.validateWithResult(input); ValidationResult output = myFhirValidator.validateWithResult(input);
assertThat(output.getMessages().size(), greaterThan(0)); assertThat(output.getMessages().size(), greaterThan(0));
assertEquals("Observation.status: minimum required = 1, but only found 0 (from http://hl7.org/fhir/StructureDefinition/Observation)", output.getMessages().get(0).getMessage()); assertEquals("Observation.status: minimum required = 1, but only found 0 (from http://hl7.org/fhir/StructureDefinition/Observation)", output.getMessages().get(0).getMessage());
@ -1189,7 +1186,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(input)); ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(input));
ValidationResult output = myVal.validateWithResult(input); ValidationResult output = myFhirValidator.validateWithResult(input);
assertEquals(output.getMessages().size(), 0); assertEquals(output.getMessages().size(), 0);
} }
@ -1206,7 +1203,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
" <text value=\"No code here!\"/>\n" + " <text value=\"No code here!\"/>\n" +
" </code>\n" + " </code>\n" +
"</Observation>"; "</Observation>";
ValidationResult output = myVal.validateWithResult(input); ValidationResult output = myFhirValidator.validateWithResult(input);
logResultsAndReturnAll(output); logResultsAndReturnAll(output);
assertEquals( assertEquals(
"The value provided ('notvalidcode') is not in the value set http://hl7.org/fhir/ValueSet/observation-status|4.0.1 (http://hl7.org/fhir/ValueSet/observation-status), and a code is required from this value set) (error message = Unknown code 'notvalidcode' for in-memory expansion of ValueSet 'http://hl7.org/fhir/ValueSet/observation-status')", "The value provided ('notvalidcode') is not in the value set http://hl7.org/fhir/ValueSet/observation-status|4.0.1 (http://hl7.org/fhir/ValueSet/observation-status), and a code is required from this value set) (error message = Unknown code 'notvalidcode' for in-memory expansion of ValueSet 'http://hl7.org/fhir/ValueSet/observation-status')",
@ -1236,7 +1233,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
" ]" + " ]" +
"}"; "}";
ourLog.info(input); ourLog.info(input);
ValidationResult output = myVal.validateWithResult(input); ValidationResult output = myFhirValidator.validateWithResult(input);
logResultsAndReturnAll(output); logResultsAndReturnAll(output);
assertEquals( assertEquals(
"", "",
@ -1253,7 +1250,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
input.setStatus(ObservationStatus.FINAL); input.setStatus(ObservationStatus.FINAL);
input.getCode().addCoding().setSystem("http://loinc.org").setCode("12345"); input.getCode().addCoding().setSystem("http://loinc.org").setCode("12345");
ValidationResult output = myVal.validateWithResult(input); ValidationResult output = myFhirValidator.validateWithResult(input);
List<SingleValidationMessage> errors = logResultsAndReturnNonInformationalOnes(output); List<SingleValidationMessage> errors = logResultsAndReturnNonInformationalOnes(output);
assertEquals(0, errors.size(), errors.toString()); assertEquals(0, errors.size(), errors.toString());
@ -1270,7 +1267,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
input.setStatus(ObservationStatus.FINAL); input.setStatus(ObservationStatus.FINAL);
input.getCode().addCoding().setSystem("http://acme.org").setCode("9988877"); input.getCode().addCoding().setSystem("http://acme.org").setCode("9988877");
ValidationResult output = myVal.validateWithResult(input); ValidationResult output = myFhirValidator.validateWithResult(input);
List<SingleValidationMessage> errors = logResultsAndReturnAll(output); List<SingleValidationMessage> errors = logResultsAndReturnAll(output);
assertThat(errors.toString(), errors.size(), greaterThan(0)); assertThat(errors.toString(), errors.size(), greaterThan(0));
assertEquals("Unknown code for 'http://acme.org#9988877'", errors.get(0).getMessage()); assertEquals("Unknown code for 'http://acme.org#9988877'", errors.get(0).getMessage());
@ -1288,7 +1285,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
input.setStatus(ObservationStatus.FINAL); input.setStatus(ObservationStatus.FINAL);
input.getCode().addCoding().setSystem("http://loinc.org").setCode("12345"); input.getCode().addCoding().setSystem("http://loinc.org").setCode("12345");
ValidationResult output = myVal.validateWithResult(input); ValidationResult output = myFhirValidator.validateWithResult(input);
List<SingleValidationMessage> errors = logResultsAndReturnNonInformationalOnes(output); List<SingleValidationMessage> errors = logResultsAndReturnNonInformationalOnes(output);
assertEquals(0, errors.size(), errors.toString()); assertEquals(0, errors.size(), errors.toString());
} }
@ -1308,7 +1305,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
input.setStatus(ObservationStatus.FINAL); input.setStatus(ObservationStatus.FINAL);
input.getCode().addCoding().setSystem("http://loinc.org").setCode("1234"); input.getCode().addCoding().setSystem("http://loinc.org").setCode("1234");
ValidationResult output = myVal.validateWithResult(input); ValidationResult output = myFhirValidator.validateWithResult(input);
List<SingleValidationMessage> errors = logResultsAndReturnNonInformationalOnes(output); List<SingleValidationMessage> errors = logResultsAndReturnNonInformationalOnes(output);
assertEquals(1, errors.size()); assertEquals(1, errors.size());
assertEquals("Unknown code for 'http://loinc.org#1234'", errors.get(0).getMessage()); assertEquals("Unknown code for 'http://loinc.org#1234'", errors.get(0).getMessage());
@ -1325,7 +1322,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
input.setStatus(ObservationStatus.FINAL); input.setStatus(ObservationStatus.FINAL);
input.getCode().addCoding().setSystem("http://acme.org").setCode("12345"); input.getCode().addCoding().setSystem("http://acme.org").setCode("12345");
ValidationResult output = myVal.validateWithResult(input); ValidationResult output = myFhirValidator.validateWithResult(input);
List<SingleValidationMessage> errors = logResultsAndReturnAll(output); List<SingleValidationMessage> errors = logResultsAndReturnAll(output);
assertEquals(0, errors.size(), errors.toString()); assertEquals(0, errors.size(), errors.toString());
} }
@ -1337,7 +1334,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
p.getText().setDiv(new XhtmlNode().setValue("<div>AA</div>")).setStatus(Narrative.NarrativeStatus.GENERATED); p.getText().setDiv(new XhtmlNode().setValue("<div>AA</div>")).setStatus(Narrative.NarrativeStatus.GENERATED);
p.addIdentifier().setSystem("http://example.com/").setValue("12345").getType().addCoding().setSystem("http://example.com/foo/bar").setCode("bar"); p.addIdentifier().setSystem("http://example.com/").setValue("12345").getType().addCoding().setSystem("http://example.com/foo/bar").setCode("bar");
ValidationResult output = myVal.validateWithResult(p); ValidationResult output = myFhirValidator.validateWithResult(p);
List<SingleValidationMessage> all = logResultsAndReturnAll(output); List<SingleValidationMessage> all = logResultsAndReturnAll(output);
assertEquals(1, all.size()); assertEquals(1, all.size());
assertEquals("Patient.identifier[0].type", all.get(0).getLocationString()); assertEquals("Patient.identifier[0].type", all.get(0).getLocationString());
@ -1352,13 +1349,13 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
addValidConcept("http://loinc.org", "8310-5"); addValidConcept("http://loinc.org", "8310-5");
Observation input = loadResource(ourCtx, Observation.class, "/r4/observation-with-body-temp-ucum.json"); Observation input = loadResource(ourCtx, Observation.class, "/r4/observation-with-body-temp-ucum.json");
ValidationResult output = myVal.validateWithResult(input); ValidationResult output = myFhirValidator.validateWithResult(input);
List<SingleValidationMessage> all = logResultsAndReturnNonInformationalOnes(output); List<SingleValidationMessage> all = logResultsAndReturnNonInformationalOnes(output);
assertThat(all, empty()); assertThat(all, empty());
// Change the unit to something not supported // Change the unit to something not supported
input.getValueQuantity().setCode("Heck"); input.getValueQuantity().setCode("Heck");
output = myVal.validateWithResult(input); output = myFhirValidator.validateWithResult(input);
all = logResultsAndReturnNonInformationalOnes(output); all = logResultsAndReturnNonInformationalOnes(output);
assertEquals(2, all.size()); assertEquals(2, all.size());
assertThat(all.get(0).getMessage(), containsString("Validation failed for 'http://unitsofmeasure.org#Heck'")); assertThat(all.get(0).getMessage(), containsString("Validation failed for 'http://unitsofmeasure.org#Heck'"));
@ -1375,7 +1372,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
o.addPerformer(new Reference(p1)); o.addPerformer(new Reference(p1));
o.addPerformer(new Reference(p2)); o.addPerformer(new Reference(p2));
ValidationResult output = myVal.validateWithResult(o); ValidationResult output = myFhirValidator.validateWithResult(o);
List<SingleValidationMessage> valMessages = logResultsAndReturnAll(output); List<SingleValidationMessage> valMessages = logResultsAndReturnAll(output);
for (SingleValidationMessage msg : valMessages) { for (SingleValidationMessage msg : valMessages) {
assertThat(msg.getMessage(), not(containsString("have a performer"))); assertThat(msg.getMessage(), not(containsString("have a performer")));
@ -1395,7 +1392,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
.setSystem("http://terminology.hl7.org/CodeSystem/v2-0203") .setSystem("http://terminology.hl7.org/CodeSystem/v2-0203")
.setCode("MR"); .setCode("MR");
ValidationResult output = myVal.validateWithResult(patient); ValidationResult output = myFhirValidator.validateWithResult(patient);
List<SingleValidationMessage> all = logResultsAndReturnAll(output); List<SingleValidationMessage> all = logResultsAndReturnAll(output);
assertEquals(0, all.size()); assertEquals(0, all.size());
} }
@ -1408,7 +1405,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
IResourceValidator.IValidatorResourceFetcher resourceFetcher = mock(IResourceValidator.IValidatorResourceFetcher.class); IResourceValidator.IValidatorResourceFetcher resourceFetcher = mock(IResourceValidator.IValidatorResourceFetcher.class);
when(resourceFetcher.validationPolicy(any(), any(), any(), any())).thenReturn(IResourceValidator.ReferenceValidationPolicy.CHECK_TYPE_IF_EXISTS); when(resourceFetcher.validationPolicy(any(), any(), any(), any())).thenReturn(IResourceValidator.ReferenceValidationPolicy.CHECK_TYPE_IF_EXISTS);
myInstanceVal.setValidatorResourceFetcher(resourceFetcher); myInstanceVal.setValidatorResourceFetcher(resourceFetcher);
myVal.validateWithResult(encoded); myFhirValidator.validateWithResult(encoded);
verify(resourceFetcher, times(15)).resolveURL(any(), any(), anyString(), anyString(), anyString()); verify(resourceFetcher, times(15)).resolveURL(any(), any(), anyString(), anyString(), anyString());
verify(resourceFetcher, times(12)).validationPolicy(any(), any(), anyString(), anyString()); verify(resourceFetcher, times(12)).validationPolicy(any(), any(), anyString(), anyString());
@ -1420,7 +1417,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
public void testValidateStructureDefinition() throws IOException { public void testValidateStructureDefinition() throws IOException {
String input = loadResource("/sdc-questionnaire.profile.xml"); String input = loadResource("/sdc-questionnaire.profile.xml");
ValidationResult output = myVal.validateWithResult(input); ValidationResult output = myFhirValidator.validateWithResult(input);
logResultsAndReturnAll(output); logResultsAndReturnAll(output);
assertEquals(3, output.getMessages().size(), output.toString()); assertEquals(3, output.getMessages().size(), output.toString());
@ -1439,7 +1436,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
" \"currency\": \"USD\"\n" + " \"currency\": \"USD\"\n" +
" }\n" + " }\n" +
"}"; "}";
ValidationResult output = myVal.validateWithResult(input); ValidationResult output = myFhirValidator.validateWithResult(input);
List<SingleValidationMessage> errors = logResultsAndReturnNonInformationalOnes(output); List<SingleValidationMessage> errors = logResultsAndReturnNonInformationalOnes(output);
assertEquals(0, errors.size(), errors.toString()); assertEquals(0, errors.size(), errors.toString());
@ -1457,7 +1454,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
" \"currency\": \"BLAH\"\n" + " \"currency\": \"BLAH\"\n" +
" }\n" + " }\n" +
"}"; "}";
ValidationResult output = myVal.validateWithResult(input); ValidationResult output = myFhirValidator.validateWithResult(input);
List<SingleValidationMessage> errors = logResultsAndReturnNonInformationalOnes(output); List<SingleValidationMessage> errors = logResultsAndReturnNonInformationalOnes(output);
assertEquals(1, errors.size(), errors.toString()); assertEquals(1, errors.size(), errors.toString());
assertThat(errors.get(0).getMessage(), containsString("The value provided ('BLAH') is not in the value set http://hl7.org/fhir/ValueSet/currencies")); assertThat(errors.get(0).getMessage(), containsString("The value provided ('BLAH') is not in the value set http://hl7.org/fhir/ValueSet/currencies"));
@ -1477,7 +1474,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
.setText("This is text") .setText("This is text")
.setAuthor(new Reference("Patient/123")); .setAuthor(new Reference("Patient/123"));
ValidationResult output = myVal.validateWithResult(allergy); ValidationResult output = myFhirValidator.validateWithResult(allergy);
List<SingleValidationMessage> errors = logResultsAndReturnNonInformationalOnes(output); List<SingleValidationMessage> errors = logResultsAndReturnNonInformationalOnes(output);
assertEquals(0, errors.size(), errors.toString()); assertEquals(0, errors.size(), errors.toString());
@ -1496,7 +1493,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
.setText("This is text") .setText("This is text")
.setAuthor(new Reference("CodeSystems/123")); .setAuthor(new Reference("CodeSystems/123"));
ValidationResult output = myVal.validateWithResult(allergy); ValidationResult output = myFhirValidator.validateWithResult(allergy);
List<SingleValidationMessage> errors = logResultsAndReturnNonInformationalOnes(output); List<SingleValidationMessage> errors = logResultsAndReturnNonInformationalOnes(output);
assertEquals(0, errors.size(), errors.toString()); assertEquals(0, errors.size(), errors.toString());
assertThat(errors.get(0).getMessage(), containsString("The value provided ('BLAH') is not in the value set http://hl7.org/fhir/ValueSet/currencies")); assertThat(errors.get(0).getMessage(), containsString("The value provided ('BLAH') is not in the value set http://hl7.org/fhir/ValueSet/currencies"));
@ -1516,30 +1513,27 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
Bundle bundle = buildBundle(entriesCount, false); Bundle bundle = buildBundle(entriesCount, false);
assertThat(bundle.getEntry(), hasSize(entriesCount)); assertThat(bundle.getEntry(), hasSize(entriesCount));
ValidationOptions validationOptions = buildValidationOptions(); try {
// Run once to exclude initialization from time myFhirValidator.setConcurrentBundleValidation(true);
myVal.validateWithResult(bundle, validationOptions); myFhirValidator.setBundleValidationThreadCount(4);
// Run once to exclude initialization from time
myFhirValidator.validateWithResult(bundle);
// execute // execute
StopWatch stopwatch = new StopWatch(); StopWatch stopwatch = new StopWatch();
ValidationResult output = myVal.validateWithResult(bundle, validationOptions); ValidationResult output = myFhirValidator.validateWithResult(bundle);
ourLog.info("Validation time: {}", stopwatch); ourLog.info("Validation time: {}", stopwatch);
// validate
// validate List<SingleValidationMessage> all = logResultsAndReturnErrorOnes(output);
List<SingleValidationMessage> all = logResultsAndReturnErrorOnes(output); assertThat(output.getMessages(), hasSize(entriesCount * 2));
assertThat(output.getMessages(), hasSize(entriesCount * 2)); // This assert proves that we did a multi-threaded validation since the outer bundle fails validation
// This assert proves that we did a multi-threaded validation since the outer bundle fails validation // due to lack of unique fullUrl values on the entries. If you setConcurrentBundleValidation(false)
// due to lack of unique fullUrl values on the entries. If you setConcurrentBundleValidation(false) // above this test will fail.
// above this test will fail. assertEquals(0, all.size(), all.toString());
assertEquals(0, all.size(), all.toString()); } finally {
} myFhirValidator.setConcurrentBundleValidation(false);
myFhirValidator.setBundleValidationThreadCount(FhirValidator.DEFAULT_BUNDLE_VALIDATION_THREADCOUNT);
@NotNull }
private ValidationOptions buildValidationOptions() {
ValidationOptions validationOptions = new ValidationOptions();
validationOptions.setConcurrentBundleValidation(true);
validationOptions.setBundleValidationThreadCount(4);
return validationOptions;
} }
private Bundle buildBundle(int theSize, boolean theValidBundle) throws IOException { private Bundle buildBundle(int theSize, boolean theValidBundle) throws IOException {

View File

@ -4,7 +4,6 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.support.DefaultProfileValidationSupport; import ca.uhn.fhir.context.support.DefaultProfileValidationSupport;
import ca.uhn.fhir.context.support.IValidationSupport; import ca.uhn.fhir.context.support.IValidationSupport;
import ca.uhn.fhir.parser.IParser; import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.util.TestUtil;
import ca.uhn.fhir.validation.FhirValidator; import ca.uhn.fhir.validation.FhirValidator;
import ca.uhn.fhir.validation.ResultSeverityEnum; import ca.uhn.fhir.validation.ResultSeverityEnum;
import ca.uhn.fhir.validation.SingleValidationMessage; import ca.uhn.fhir.validation.SingleValidationMessage;