Correct Validation Performance Regression (#1895)
* Validation performance regression * Optimize validation * More cleanup * Add changelog * Test fixes * Build fixes
This commit is contained in:
parent
926afd01f2
commit
0d3ad622b5
|
@ -20,6 +20,9 @@ package ca.uhn.fhir.context.support;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
|
||||
public class ConceptValidationOptions {
|
||||
|
||||
public boolean isInferSystem() {
|
||||
|
@ -33,4 +36,10 @@ public class ConceptValidationOptions {
|
|||
|
||||
private boolean myInferSystem;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
|
||||
.append("inferSystem", myInferSystem)
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
type: fix
|
||||
issue: 1895
|
||||
title: "HAPI FHIR 5.0.0 introduced a regressin in JPA validator performance, where a number of unnecessary database lookups
|
||||
were introduced. This has been corrected."
|
|
@ -114,6 +114,7 @@ import java.util.Date;
|
|||
public abstract class BaseConfig {
|
||||
|
||||
public static final String JPA_VALIDATION_SUPPORT_CHAIN = "myJpaValidationSupportChain";
|
||||
public static final String JPA_VALIDATION_SUPPORT = "myJpaValidationSupport";
|
||||
public static final String TASK_EXECUTOR_NAME = "hapiJpaTaskExecutor";
|
||||
public static final String GRAPHQL_PROVIDER_NAME = "myGraphQLProvider";
|
||||
public static final String PERSISTED_JPA_BUNDLE_PROVIDER = "PersistedJpaBundleProvider";
|
||||
|
|
|
@ -65,16 +65,16 @@ public abstract class BaseConfigDstu3Plus extends BaseConfig {
|
|||
public abstract ITermVersionAdapterSvc terminologyVersionAdapterSvc();
|
||||
|
||||
@Bean(name = "myDefaultProfileValidationSupport")
|
||||
public IValidationSupport defaultProfileValidationSupport() {
|
||||
public DefaultProfileValidationSupport defaultProfileValidationSupport() {
|
||||
return new DefaultProfileValidationSupport(fhirContext());
|
||||
}
|
||||
|
||||
@Bean(name = JPA_VALIDATION_SUPPORT_CHAIN)
|
||||
public ValidationSupportChain jpaValidationSupportChain() {
|
||||
public JpaValidationSupportChain jpaValidationSupportChain() {
|
||||
return new JpaValidationSupportChain(fhirContext());
|
||||
}
|
||||
|
||||
@Bean(name = "myJpaValidationSupport")
|
||||
@Bean(name = JPA_VALIDATION_SUPPORT)
|
||||
public IValidationSupport jpaValidationSupport() {
|
||||
return new JpaPersistedResourceValidationSupport(fhirContext());
|
||||
}
|
||||
|
|
|
@ -86,28 +86,30 @@ public class BaseDstu2Config extends BaseConfig {
|
|||
|
||||
@Bean(name = "myInstanceValidator")
|
||||
@Lazy
|
||||
public IInstanceValidatorModule instanceValidator() {
|
||||
ValidationSupportChain validationSupportChain = validationSupportChain();
|
||||
CachingValidationSupport cachingValidationSupport = new CachingValidationSupport(new HapiToHl7OrgDstu2ValidatingSupportWrapper(validationSupportChain));
|
||||
public IInstanceValidatorModule instanceValidator(ValidationSupportChain theValidationSupportChain) {
|
||||
CachingValidationSupport cachingValidationSupport = new CachingValidationSupport(new HapiToHl7OrgDstu2ValidatingSupportWrapper(theValidationSupportChain));
|
||||
FhirInstanceValidator retVal = new FhirInstanceValidator(cachingValidationSupport);
|
||||
retVal.setBestPracticeWarningLevel(IResourceValidator.BestPracticeWarningLevel.Warning);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Bean(name = "myDefaultProfileValidationSupport")
|
||||
public DefaultProfileValidationSupport defaultProfileValidationSupport() {
|
||||
return new DefaultProfileValidationSupport(fhirContext());
|
||||
}
|
||||
|
||||
@Bean(name = JPA_VALIDATION_SUPPORT_CHAIN)
|
||||
public ValidationSupportChain validationSupportChain() {
|
||||
DefaultProfileValidationSupport defaultProfileValidationSupport = new DefaultProfileValidationSupport(fhirContext());
|
||||
public ValidationSupportChain validationSupportChain(DefaultProfileValidationSupport theDefaultProfileValidationSupport) {
|
||||
InMemoryTerminologyServerValidationSupport inMemoryTerminologyServer = new InMemoryTerminologyServerValidationSupport(fhirContextDstu2());
|
||||
IValidationSupport jpaValidationSupport = jpaValidationSupportDstu2();
|
||||
CommonCodeSystemsTerminologyService commonCodeSystemsTermSvc = new CommonCodeSystemsTerminologyService(fhirContext());
|
||||
return new ValidationSupportChain(defaultProfileValidationSupport, jpaValidationSupport, inMemoryTerminologyServer, commonCodeSystemsTermSvc);
|
||||
return new ValidationSupportChain(theDefaultProfileValidationSupport, jpaValidationSupport, inMemoryTerminologyServer, commonCodeSystemsTermSvc);
|
||||
}
|
||||
|
||||
@Primary
|
||||
@Bean
|
||||
@Bean(name = JPA_VALIDATION_SUPPORT)
|
||||
public IValidationSupport jpaValidationSupportDstu2() {
|
||||
JpaPersistedResourceValidationSupport retVal = new JpaPersistedResourceValidationSupport(fhirContextDstu2());
|
||||
return retVal;
|
||||
return new JpaPersistedResourceValidationSupport(fhirContextDstu2());
|
||||
}
|
||||
|
||||
@Bean(name = "myResourceCountsCache")
|
||||
|
|
|
@ -28,6 +28,8 @@ import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
|||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
import ca.uhn.fhir.rest.param.UriParam;
|
||||
import com.github.benmanes.caffeine.cache.Cache;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
@ -43,6 +45,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.transaction.Transactional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
||||
|
@ -57,6 +60,7 @@ public class JpaPersistedResourceValidationSupport implements IValidationSupport
|
|||
private static final Logger ourLog = LoggerFactory.getLogger(JpaPersistedResourceValidationSupport.class);
|
||||
|
||||
private final FhirContext myFhirContext;
|
||||
private final IBaseResource myNoMatch;
|
||||
|
||||
@Autowired
|
||||
private DaoRegistry myDaoRegistry;
|
||||
|
@ -65,6 +69,7 @@ public class JpaPersistedResourceValidationSupport implements IValidationSupport
|
|||
private Class<? extends IBaseResource> myValueSetType;
|
||||
private Class<? extends IBaseResource> myQuestionnaireType;
|
||||
private Class<? extends IBaseResource> myImplementationGuideType;
|
||||
private Cache<String, IBaseResource> myLoadCache = Caffeine.newBuilder().expireAfterWrite(1, TimeUnit.MINUTES).build();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
|
@ -73,6 +78,8 @@ public class JpaPersistedResourceValidationSupport implements IValidationSupport
|
|||
super();
|
||||
Validate.notNull(theFhirContext);
|
||||
myFhirContext = theFhirContext;
|
||||
|
||||
myNoMatch = myFhirContext.getResourceDefinition("Basic").newInstance();
|
||||
}
|
||||
|
||||
|
||||
|
@ -99,77 +106,86 @@ public class JpaPersistedResourceValidationSupport implements IValidationSupport
|
|||
return null;
|
||||
}
|
||||
|
||||
IdType id = new IdType(theUri);
|
||||
boolean localReference = false;
|
||||
if (id.hasBaseUrl() == false && id.hasIdPart() == true) {
|
||||
localReference = true;
|
||||
}
|
||||
String key = theClass.getSimpleName() + " " + theUri;
|
||||
IBaseResource fetched = myLoadCache.get(key, t -> {
|
||||
IdType id = new IdType(theUri);
|
||||
boolean localReference = false;
|
||||
if (id.hasBaseUrl() == false && id.hasIdPart() == true) {
|
||||
localReference = true;
|
||||
}
|
||||
|
||||
String resourceName = myFhirContext.getResourceType(theClass);
|
||||
IBundleProvider search;
|
||||
if ("ValueSet".equals(resourceName)) {
|
||||
if (localReference) {
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.setLoadSynchronousUpTo(1);
|
||||
params.add(IAnyResource.SP_RES_ID, new StringParam(theUri));
|
||||
search = myDaoRegistry.getResourceDao("ValueSet").search(params);
|
||||
if (search.size() == 0) {
|
||||
params = new SearchParameterMap();
|
||||
String resourceName = myFhirContext.getResourceType(theClass);
|
||||
IBundleProvider search;
|
||||
if ("ValueSet".equals(resourceName)) {
|
||||
if (localReference) {
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.setLoadSynchronousUpTo(1);
|
||||
params.add(IAnyResource.SP_RES_ID, new StringParam(theUri));
|
||||
search = myDaoRegistry.getResourceDao("ValueSet").search(params);
|
||||
if (search.size() == 0) {
|
||||
params = new SearchParameterMap();
|
||||
params.setLoadSynchronousUpTo(1);
|
||||
params.add(ValueSet.SP_URL, new UriParam(theUri));
|
||||
search = myDaoRegistry.getResourceDao("ValueSet").search(params);
|
||||
}
|
||||
} else {
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.setLoadSynchronousUpTo(1);
|
||||
params.add(ValueSet.SP_URL, new UriParam(theUri));
|
||||
search = myDaoRegistry.getResourceDao("ValueSet").search(params);
|
||||
}
|
||||
} else {
|
||||
} else if ("StructureDefinition".equals(resourceName)) {
|
||||
// Don't allow the core FHIR definitions to be overwritten
|
||||
if (theUri.startsWith("http://hl7.org/fhir/StructureDefinition/")) {
|
||||
String typeName = theUri.substring("http://hl7.org/fhir/StructureDefinition/".length());
|
||||
if (myFhirContext.getElementDefinition(typeName) != null) {
|
||||
return myNoMatch;
|
||||
}
|
||||
}
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.setLoadSynchronousUpTo(1);
|
||||
params.add(ValueSet.SP_URL, new UriParam(theUri));
|
||||
search = myDaoRegistry.getResourceDao("ValueSet").search(params);
|
||||
}
|
||||
} else if ("StructureDefinition".equals(resourceName)) {
|
||||
// Don't allow the core FHIR definitions to be overwritten
|
||||
if (theUri.startsWith("http://hl7.org/fhir/StructureDefinition/")) {
|
||||
String typeName = theUri.substring("http://hl7.org/fhir/StructureDefinition/".length());
|
||||
if (myFhirContext.getElementDefinition(typeName) != null) {
|
||||
return null;
|
||||
params.add(StructureDefinition.SP_URL, new UriParam(theUri));
|
||||
search = myDaoRegistry.getResourceDao("StructureDefinition").search(params);
|
||||
} else if ("Questionnaire".equals(resourceName)) {
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.setLoadSynchronousUpTo(1);
|
||||
if (localReference || myFhirContext.getVersion().getVersion().isEquivalentTo(FhirVersionEnum.DSTU2)) {
|
||||
params.add(IAnyResource.SP_RES_ID, new StringParam(id.getIdPart()));
|
||||
} else {
|
||||
params.add(Questionnaire.SP_URL, new UriParam(id.getValue()));
|
||||
}
|
||||
}
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.setLoadSynchronousUpTo(1);
|
||||
params.add(StructureDefinition.SP_URL, new UriParam(theUri));
|
||||
search = myDaoRegistry.getResourceDao("StructureDefinition").search(params);
|
||||
} else if ("Questionnaire".equals(resourceName)) {
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.setLoadSynchronousUpTo(1);
|
||||
if (localReference || myFhirContext.getVersion().getVersion().isEquivalentTo(FhirVersionEnum.DSTU2)) {
|
||||
params.add(IAnyResource.SP_RES_ID, new StringParam(id.getIdPart()));
|
||||
search = myDaoRegistry.getResourceDao("Questionnaire").search(params);
|
||||
} else if ("CodeSystem".equals(resourceName)) {
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.setLoadSynchronousUpTo(1);
|
||||
params.add(CodeSystem.SP_URL, new UriParam(theUri));
|
||||
search = myDaoRegistry.getResourceDao(resourceName).search(params);
|
||||
} else if ("ImplementationGuide".equals(resourceName)) {
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.setLoadSynchronousUpTo(1);
|
||||
params.add(ImplementationGuide.SP_URL, new UriParam(theUri));
|
||||
search = myDaoRegistry.getResourceDao("ImplementationGuide").search(params);
|
||||
} else {
|
||||
params.add(Questionnaire.SP_URL, new UriParam(id.getValue()));
|
||||
throw new IllegalArgumentException("Can't fetch resource type: " + resourceName);
|
||||
}
|
||||
search = myDaoRegistry.getResourceDao("Questionnaire").search(params);
|
||||
} else if ("CodeSystem".equals(resourceName)) {
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.setLoadSynchronousUpTo(1);
|
||||
params.add(CodeSystem.SP_URL, new UriParam(theUri));
|
||||
search = myDaoRegistry.getResourceDao(resourceName).search(params);
|
||||
} else if ("ImplementationGuide".equals(resourceName)) {
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.setLoadSynchronousUpTo(1);
|
||||
params.add(ImplementationGuide.SP_URL, new UriParam(theUri));
|
||||
search = myDaoRegistry.getResourceDao("ImplementationGuide").search(params);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Can't fetch resource type: " + resourceName);
|
||||
}
|
||||
|
||||
Integer size = search.size();
|
||||
if (size == null || size == 0) {
|
||||
Integer size = search.size();
|
||||
if (size == null || size == 0) {
|
||||
return myNoMatch;
|
||||
}
|
||||
|
||||
if (size > 1) {
|
||||
ourLog.warn("Found multiple {} instances with URL search value of: {}", resourceName, theUri);
|
||||
}
|
||||
|
||||
return search.getResources(0, 1).get(0);
|
||||
});
|
||||
|
||||
if (fetched == myNoMatch) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (size > 1) {
|
||||
ourLog.warn("Found multiple {} instances with URL search value of: {}", resourceName, theUri);
|
||||
}
|
||||
|
||||
return (T) search.getResources(0, 1).get(0);
|
||||
return (T) fetched;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -192,4 +208,7 @@ public class JpaPersistedResourceValidationSupport implements IValidationSupport
|
|||
}
|
||||
|
||||
|
||||
public void clearCaches() {
|
||||
myLoadCache.invalidateAll();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,19 @@ import org.apache.commons.lang3.builder.HashCodeBuilder;
|
|||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
|
||||
import javax.persistence.*;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.ForeignKey;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.OneToOne;
|
||||
import javax.persistence.SequenceGenerator;
|
||||
import javax.persistence.Table;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
@ -127,6 +139,11 @@ public class TermCodeSystemVersion implements Serializable {
|
|||
return this;
|
||||
}
|
||||
|
||||
public TermCodeSystemVersion setId(Long theId) {
|
||||
myId = theId;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object theO) {
|
||||
if (this == theO) {
|
||||
|
|
|
@ -22,6 +22,7 @@ package ca.uhn.fhir.jpa.term;
|
|||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.support.ConceptValidationOptions;
|
||||
import ca.uhn.fhir.context.support.DefaultProfileValidationSupport;
|
||||
import ca.uhn.fhir.context.support.IValidationSupport;
|
||||
import ca.uhn.fhir.context.support.ValidationSupportContext;
|
||||
import ca.uhn.fhir.context.support.ValueSetExpansionOptions;
|
||||
|
@ -173,8 +174,11 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
|||
public static final int DEFAULT_FETCH_SIZE = 250;
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseTermReadSvcImpl.class);
|
||||
private static final ValueSetExpansionOptions DEFAULT_EXPANSION_OPTIONS = new ValueSetExpansionOptions();
|
||||
private static final TermCodeSystemVersion NO_CURRENT_VERSION = new TermCodeSystemVersion().setId(-1L);
|
||||
private static boolean ourLastResultsFromTranslationCache; // For testing.
|
||||
private static boolean ourLastResultsFromTranslationWithReverseCache; // For testing.
|
||||
private final int myFetchSize = DEFAULT_FETCH_SIZE;
|
||||
private final Cache<String, TermCodeSystemVersion> myCodeSystemCurrentVersionCache = Caffeine.newBuilder().expireAfterWrite(1, TimeUnit.MINUTES).build();
|
||||
@Autowired
|
||||
protected DaoRegistry myDaoRegistry;
|
||||
@Autowired
|
||||
|
@ -209,7 +213,6 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
|||
private DaoConfig myDaoConfig;
|
||||
private Cache<TranslationQuery, List<TermConceptMapGroupElementTarget>> myTranslationCache;
|
||||
private Cache<TranslationQuery, List<TermConceptMapGroupElement>> myTranslationWithReverseCache;
|
||||
private final int myFetchSize = DEFAULT_FETCH_SIZE;
|
||||
private TransactionTemplate myTxTemplate;
|
||||
@Autowired
|
||||
private PlatformTransactionManager myTransactionManager;
|
||||
|
@ -227,12 +230,15 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
|||
private ITermCodeSystemStorageSvc myConceptStorageSvc;
|
||||
@Autowired
|
||||
private ApplicationContext myApplicationContext;
|
||||
@Autowired
|
||||
private DefaultProfileValidationSupport myDefaultProfileValidationSupport;
|
||||
private volatile IValidationSupport myJpaValidationSupport;
|
||||
private volatile IValidationSupport myValidationSupport;
|
||||
|
||||
@Override
|
||||
public boolean isCodeSystemSupported(ValidationSupportContext theValidationSupportContext, String theSystem) {
|
||||
return supportsSystem(theSystem);
|
||||
TermCodeSystemVersion cs = getCurrentCodeSystemVersion(theSystem);
|
||||
return cs != null;
|
||||
}
|
||||
|
||||
private void addCodeIfNotAlreadyAdded(IValueSetConceptAccumulator theValueSetCodeAccumulator, Set<String> theAddedCodes, TermConcept theConcept, boolean theAdd, AtomicInteger theCodeCounter) {
|
||||
|
@ -283,16 +289,10 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
|||
* This method is present only for unit tests, do not call from client code
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public void clearTranslationCache() {
|
||||
public void clearCaches() {
|
||||
myTranslationCache.invalidateAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is present only for unit tests, do not call from client code
|
||||
*/
|
||||
@VisibleForTesting()
|
||||
public void clearTranslationWithReverseCache() {
|
||||
myTranslationWithReverseCache.invalidateAll();
|
||||
myCodeSystemCurrentVersionCache.invalidateAll();
|
||||
}
|
||||
|
||||
public void deleteConceptMap(ResourceTable theResourceTable) {
|
||||
|
@ -1289,15 +1289,35 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
|||
TransactionTemplate txTemplate = new TransactionTemplate(myTransactionManager);
|
||||
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_MANDATORY);
|
||||
return txTemplate.execute(t -> {
|
||||
TermCodeSystemVersion csv = null;
|
||||
TermCodeSystem cs = myCodeSystemDao.findByCodeSystemUri(theCodeSystem);
|
||||
if (cs != null && cs.getCurrentVersion() != null) {
|
||||
csv = cs.getCurrentVersion();
|
||||
TermCodeSystemVersion csv = getCurrentCodeSystemVersion(theCodeSystem);
|
||||
if (csv == null) {
|
||||
return null;
|
||||
}
|
||||
return myConceptDao.findByCodeSystemAndCode(csv, theCode);
|
||||
});
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private TermCodeSystemVersion getCurrentCodeSystemVersion(String theUri) {
|
||||
TermCodeSystemVersion retVal = myCodeSystemCurrentVersionCache.get(theUri, uri -> {
|
||||
TermCodeSystemVersion csv = null;
|
||||
TermCodeSystem cs = myCodeSystemDao.findByCodeSystemUri(uri);
|
||||
if (cs != null && cs.getCurrentVersion() != null) {
|
||||
csv = cs.getCurrentVersion();
|
||||
}
|
||||
if (csv != null) {
|
||||
return csv;
|
||||
} else {
|
||||
return NO_CURRENT_VERSION;
|
||||
}
|
||||
});
|
||||
if (retVal == NO_CURRENT_VERSION) {
|
||||
return null;
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
@Transactional(propagation = Propagation.REQUIRED)
|
||||
@Override
|
||||
public Set<TermConcept> findCodesAbove(Long theCodeSystemResourcePid, Long theCodeSystemVersionPid, String theCode) {
|
||||
|
@ -1715,12 +1735,6 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsSystem(String theSystem) {
|
||||
TermCodeSystem cs = getCodeSystem(theSystem);
|
||||
return cs != null;
|
||||
}
|
||||
|
||||
private ArrayList<VersionIndependentConcept> toVersionIndependentConcepts(String theSystem, Set<TermConcept> codes) {
|
||||
ArrayList<VersionIndependentConcept> retVal = new ArrayList<>(codes.size());
|
||||
for (TermConcept next : codes) {
|
||||
|
|
|
@ -94,8 +94,6 @@ public interface ITermReadSvc extends IValidationSupport {
|
|||
|
||||
void storeTermValueSet(ResourceTable theResourceTable, ValueSet theValueSet);
|
||||
|
||||
boolean supportsSystem(String theCodeSystem);
|
||||
|
||||
List<TermConceptMapGroupElementTarget> translate(TranslationRequest theTranslationRequest);
|
||||
|
||||
List<TermConceptMapGroupElement> translateWithReverse(TranslationRequest theTranslationRequest);
|
||||
|
|
|
@ -63,12 +63,12 @@ public class JpaValidationSupportChain extends ValidationSupportChain {
|
|||
|
||||
@PostConstruct
|
||||
public void postConstruct() {
|
||||
addValidationSupport((IValidationSupport) new CommonCodeSystemsTerminologyService(myFhirContext));
|
||||
addValidationSupport(new CommonCodeSystemsTerminologyService(myFhirContext));
|
||||
addValidationSupport(myDefaultProfileValidationSupport);
|
||||
addValidationSupport(myJpaValidationSupport);
|
||||
addValidationSupport((IValidationSupport) myTerminologyService);
|
||||
addValidationSupport((IValidationSupport) new SnapshotGeneratingValidationSupport(myFhirContext));
|
||||
addValidationSupport((IValidationSupport) new InMemoryTerminologyServerValidationSupport(myFhirContext));
|
||||
addValidationSupport(myTerminologyService);
|
||||
addValidationSupport(new SnapshotGeneratingValidationSupport(myFhirContext));
|
||||
addValidationSupport(new InMemoryTerminologyServerValidationSupport(myFhirContext));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import ca.uhn.fhir.jpa.search.LuceneSearchMappingFactory;
|
|||
import ca.uhn.fhir.jpa.util.CircularQueueCaptureQueriesListener;
|
||||
import ca.uhn.fhir.jpa.util.CurrentThreadCaptureQueriesListener;
|
||||
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
|
||||
import ca.uhn.fhir.validation.IInstanceValidatorModule;
|
||||
import ca.uhn.fhir.validation.ResultSeverityEnum;
|
||||
import net.ttddyy.dsproxy.listener.ThreadQueryCountHolder;
|
||||
import net.ttddyy.dsproxy.support.ProxyDataSourceBuilder;
|
||||
|
@ -152,12 +153,12 @@ public class TestDstu2Config extends BaseJavaConfigDstu2 {
|
|||
*/
|
||||
@Bean
|
||||
@Lazy
|
||||
public RequestValidatingInterceptor requestValidatingInterceptor() {
|
||||
public RequestValidatingInterceptor requestValidatingInterceptor(IInstanceValidatorModule theInstanceValidator) {
|
||||
RequestValidatingInterceptor requestValidator = new RequestValidatingInterceptor();
|
||||
requestValidator.setFailOnSeverity(ResultSeverityEnum.ERROR);
|
||||
requestValidator.setAddResponseHeaderOnSeverity(null);
|
||||
requestValidator.setAddResponseOutcomeHeaderOnSeverity(ResultSeverityEnum.INFORMATION);
|
||||
requestValidator.addValidatorModule(instanceValidator());
|
||||
requestValidator.addValidatorModule(theInstanceValidator);
|
||||
|
||||
return requestValidator;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package ca.uhn.fhir.jpa.dao;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.support.IValidationSupport;
|
||||
import ca.uhn.fhir.interceptor.api.IInterceptorService;
|
||||
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||
import ca.uhn.fhir.interceptor.executor.InterceptorService;
|
||||
|
@ -9,6 +10,7 @@ import ca.uhn.fhir.jpa.api.dao.IFhirSystemDao;
|
|||
import ca.uhn.fhir.jpa.api.model.ExpungeOptions;
|
||||
import ca.uhn.fhir.jpa.api.svc.ISearchCoordinatorSvc;
|
||||
import ca.uhn.fhir.jpa.bulk.IBulkDataExportSvc;
|
||||
import ca.uhn.fhir.jpa.config.BaseConfig;
|
||||
import ca.uhn.fhir.jpa.dao.index.IdHelperService;
|
||||
import ca.uhn.fhir.jpa.entity.TermConcept;
|
||||
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
||||
|
@ -30,6 +32,7 @@ import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
|||
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||
import ca.uhn.fhir.test.BaseTest;
|
||||
import ca.uhn.fhir.test.utilities.LoggingRule;
|
||||
import ca.uhn.fhir.test.utilities.ProxyUtil;
|
||||
import ca.uhn.fhir.test.utilities.UnregisterScheduledProcessor;
|
||||
import ca.uhn.fhir.util.BundleUtil;
|
||||
import ca.uhn.fhir.util.StopWatch;
|
||||
|
@ -54,6 +57,8 @@ import org.mockito.Answers;
|
|||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
|
@ -125,6 +130,10 @@ public abstract class BaseJpaTest extends BaseTest {
|
|||
private IdHelperService myIdHelperService;
|
||||
@Autowired
|
||||
private MemoryCacheService myMemoryCacheService;
|
||||
@Qualifier(BaseConfig.JPA_VALIDATION_SUPPORT)
|
||||
@Autowired
|
||||
private IValidationSupport myJpaPersistedValidationSupport;
|
||||
|
||||
|
||||
@After
|
||||
public void afterPerformCleanup() {
|
||||
|
@ -138,6 +147,11 @@ public abstract class BaseJpaTest extends BaseTest {
|
|||
if (myMemoryCacheService != null) {
|
||||
myMemoryCacheService.invalidateAllCaches();
|
||||
}
|
||||
if (myJpaPersistedValidationSupport != null) {
|
||||
ProxyUtil.getSingletonTarget(myJpaPersistedValidationSupport, JpaPersistedResourceValidationSupport.class).clearCaches();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@After
|
||||
|
|
|
@ -353,8 +353,7 @@ public abstract class BaseJpaDstu3Test extends BaseJpaTest {
|
|||
@After
|
||||
public void afterClearTerminologyCaches() {
|
||||
BaseTermReadSvcImpl baseHapiTerminologySvc = AopTestUtils.getTargetObject(myTermSvc);
|
||||
baseHapiTerminologySvc.clearTranslationCache();
|
||||
baseHapiTerminologySvc.clearTranslationWithReverseCache();
|
||||
baseHapiTerminologySvc.clearCaches();
|
||||
BaseTermReadSvcImpl.clearOurLastResultsFromTranslationCache();
|
||||
BaseTermReadSvcImpl.clearOurLastResultsFromTranslationWithReverseCache();
|
||||
TermDeferredStorageSvcImpl deferredSvc = AopTestUtils.getTargetObject(myTerminologyDeferredStorageSvc);
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
package ca.uhn.fhir.jpa.dao.dstu3;
|
||||
|
||||
import ca.uhn.fhir.context.support.IValidationSupport;
|
||||
import ca.uhn.fhir.jpa.config.BaseConfig;
|
||||
import ca.uhn.fhir.jpa.dao.JpaPersistedResourceValidationSupport;
|
||||
import ca.uhn.fhir.jpa.util.TestUtil;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
|
@ -7,6 +10,7 @@ import ca.uhn.fhir.rest.api.ValidationModeEnum;
|
|||
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import ca.uhn.fhir.test.utilities.ProxyUtil;
|
||||
import ca.uhn.fhir.util.StopWatch;
|
||||
import ca.uhn.fhir.validation.IValidatorModule;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
@ -23,6 +27,7 @@ import org.junit.AfterClass;
|
|||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.test.util.AopTestUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -40,6 +45,9 @@ public class FhirResourceDaoDstu3ValidateTest extends BaseJpaDstu3Test {
|
|||
private CachingValidationSupport myValidationSupport;
|
||||
@Autowired
|
||||
private FhirInstanceValidator myFhirInstanceValidator;
|
||||
@Autowired
|
||||
@Qualifier(BaseConfig.JPA_VALIDATION_SUPPORT)
|
||||
private IValidationSupport myPersistedResourceValidationSupport;
|
||||
|
||||
@Test
|
||||
public void testValidateChangedQuestionnaire() {
|
||||
|
@ -78,6 +86,7 @@ public class FhirResourceDaoDstu3ValidateTest extends BaseJpaDstu3Test {
|
|||
ourLog.info("Clearing cache");
|
||||
myValidationSupport.invalidateCaches();
|
||||
myFhirInstanceValidator.invalidateCaches();
|
||||
ProxyUtil.getSingletonTarget(myPersistedResourceValidationSupport, JpaPersistedResourceValidationSupport.class).clearCaches();
|
||||
|
||||
try {
|
||||
myQuestionnaireResponseDao.validate(qr, null, null, null, null, null, null);
|
||||
|
|
|
@ -482,8 +482,7 @@ public abstract class BaseJpaR4Test extends BaseJpaTest implements ITestDataBui
|
|||
@After
|
||||
public void afterClearTerminologyCaches() {
|
||||
BaseTermReadSvcImpl baseHapiTerminologySvc = AopTestUtils.getTargetObject(myTermSvc);
|
||||
baseHapiTerminologySvc.clearTranslationCache();
|
||||
baseHapiTerminologySvc.clearTranslationWithReverseCache();
|
||||
baseHapiTerminologySvc.clearCaches();
|
||||
BaseTermReadSvcImpl.clearOurLastResultsFromTranslationCache();
|
||||
BaseTermReadSvcImpl.clearOurLastResultsFromTranslationWithReverseCache();
|
||||
TermDeferredStorageSvcImpl termDeferredStorageSvc = AopTestUtils.getTargetObject(myTerminologyDeferredStorageSvc);
|
||||
|
|
|
@ -9,11 +9,16 @@ import ca.uhn.fhir.rest.param.ReferenceParam;
|
|||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.r4.model.Bundle;
|
||||
import org.hl7.fhir.r4.model.CodeSystem;
|
||||
import org.hl7.fhir.r4.model.DateTimeType;
|
||||
import org.hl7.fhir.r4.model.IdType;
|
||||
import org.hl7.fhir.r4.model.Narrative;
|
||||
import org.hl7.fhir.r4.model.Observation;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.hl7.fhir.r4.model.Practitioner;
|
||||
import org.hl7.fhir.r4.model.Reference;
|
||||
import org.hl7.fhir.r4.model.ServiceRequest;
|
||||
import org.hl7.fhir.r4.model.StringType;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
|
@ -25,7 +30,6 @@ import static org.hamcrest.Matchers.containsInAnyOrder;
|
|||
import static org.hamcrest.Matchers.empty;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.contains;
|
||||
|
||||
public class FhirResourceDaoR4QueryCountTest extends BaseJpaR4Test {
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoR4QueryCountTest.class);
|
||||
|
@ -114,6 +118,56 @@ public class FhirResourceDaoR4QueryCountTest extends BaseJpaR4Test {
|
|||
assertEquals(0, myCaptureQueriesListener.getDeleteQueriesForCurrentThread().size());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testValidate() {
|
||||
|
||||
CodeSystem cs = new CodeSystem();
|
||||
cs.setUrl("http://foo/cs");
|
||||
cs.setContent(CodeSystem.CodeSystemContentMode.COMPLETE);
|
||||
cs.addConcept().setCode("bar-1").setDisplay("Bar 1");
|
||||
cs.addConcept().setCode("bar-2").setDisplay("Bar 2");
|
||||
myCodeSystemDao.create(cs);
|
||||
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(cs));
|
||||
|
||||
Observation obs = new Observation();
|
||||
// obs.getMeta().addProfile("http://example.com/fhir/StructureDefinition/vitalsigns-2");
|
||||
obs.getText().setStatus(Narrative.NarrativeStatus.GENERATED).setDivAsString("<div>Hello</div>");
|
||||
obs.getCategoryFirstRep().addCoding().setSystem("http://terminology.hl7.org/CodeSystem/observation-category").setCode("vital-signs");
|
||||
obs.setSubject(new Reference("Patient/123"));
|
||||
obs.addPerformer(new Reference("Practitioner/123"));
|
||||
obs.setEffective(DateTimeType.now());
|
||||
obs.setStatus(Observation.ObservationStatus.FINAL);
|
||||
obs.setValue(new StringType("This is the value"));
|
||||
obs.getCode().addCoding().setSystem("http://foo/cs").setCode("bar-1");
|
||||
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs));
|
||||
|
||||
// Validate once
|
||||
myCaptureQueriesListener.clear();
|
||||
myObservationDao.validate(obs, null, null, null, null, null, null);
|
||||
myCaptureQueriesListener.logSelectQueriesForCurrentThread();
|
||||
assertEquals(8, myCaptureQueriesListener.getSelectQueriesForCurrentThread().size());
|
||||
myCaptureQueriesListener.logUpdateQueriesForCurrentThread();
|
||||
assertEquals(0, myCaptureQueriesListener.getUpdateQueriesForCurrentThread().size());
|
||||
myCaptureQueriesListener.logInsertQueriesForCurrentThread();
|
||||
assertEquals(0, myCaptureQueriesListener.getInsertQueriesForCurrentThread().size());
|
||||
myCaptureQueriesListener.logDeleteQueriesForCurrentThread();
|
||||
assertEquals(0, myCaptureQueriesListener.getDeleteQueriesForCurrentThread().size());
|
||||
|
||||
// Validate again (should rely only on caches)
|
||||
myCaptureQueriesListener.clear();
|
||||
myObservationDao.validate(obs, null, null, null, null, null, null);
|
||||
myCaptureQueriesListener.logSelectQueriesForCurrentThread();
|
||||
assertEquals(0, myCaptureQueriesListener.getSelectQueriesForCurrentThread().size());
|
||||
myCaptureQueriesListener.logUpdateQueriesForCurrentThread();
|
||||
assertEquals(0, myCaptureQueriesListener.getUpdateQueriesForCurrentThread().size());
|
||||
myCaptureQueriesListener.logInsertQueriesForCurrentThread();
|
||||
assertEquals(0, myCaptureQueriesListener.getInsertQueriesForCurrentThread().size());
|
||||
myCaptureQueriesListener.logDeleteQueriesForCurrentThread();
|
||||
assertEquals(0, myCaptureQueriesListener.getDeleteQueriesForCurrentThread().size());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testVRead() {
|
||||
IIdType id = runInTransaction(() -> {
|
||||
|
@ -488,8 +542,6 @@ public class FhirResourceDaoR4QueryCountTest extends BaseJpaR4Test {
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testTransactionWithMultipleReferences() {
|
||||
Bundle input = new Bundle();
|
||||
|
|
|
@ -136,6 +136,27 @@ public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test {
|
|||
oo = validateAndReturnOutcome(obs);
|
||||
assertEquals(encode(oo), "Unknown code 'http://terminology.hl7.org/CodeSystem/observation-category#FOO'", oo.getIssueFirstRep().getDiagnostics());
|
||||
|
||||
// Make sure we're caching the validations as opposed to hitting the DB every time
|
||||
myCaptureQueriesListener.clear();
|
||||
obs.getText().setStatus(Narrative.NarrativeStatus.GENERATED);
|
||||
obs.getCode().getCoding().clear();
|
||||
obs.getCategory().clear();
|
||||
obs.getCategoryFirstRep().addCoding().setSystem("http://terminology.hl7.org/CodeSystem/observation-category").setCode("vital-signs");
|
||||
obs.getCode().getCodingFirstRep().setSystem("http://loinc.org").setCode("CODE4").setDisplay("Display 3");
|
||||
oo = validateAndReturnOutcome(obs);
|
||||
assertEquals(encode(oo), "No issues detected during validation", oo.getIssueFirstRep().getDiagnostics());
|
||||
myCaptureQueriesListener.logSelectQueriesForCurrentThread();
|
||||
|
||||
myCaptureQueriesListener.clear();
|
||||
obs.getText().setStatus(Narrative.NarrativeStatus.GENERATED);
|
||||
obs.getCode().getCodingFirstRep().setSystem("http://loinc.org").setCode("CODE4").setDisplay("Display 3");
|
||||
oo = validateAndReturnOutcome(obs);
|
||||
assertEquals(encode(oo), "No issues detected during validation", oo.getIssueFirstRep().getDiagnostics());
|
||||
myCaptureQueriesListener.logSelectQueriesForCurrentThread();
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -429,8 +429,7 @@ public abstract class BaseJpaR5Test extends BaseJpaTest {
|
|||
@After
|
||||
public void afterClearTerminologyCaches() {
|
||||
BaseTermReadSvcImpl baseHapiTerminologySvc = AopTestUtils.getTargetObject(myTermSvc);
|
||||
baseHapiTerminologySvc.clearTranslationCache();
|
||||
baseHapiTerminologySvc.clearTranslationWithReverseCache();
|
||||
baseHapiTerminologySvc.clearCaches();
|
||||
BaseTermReadSvcImpl.clearOurLastResultsFromTranslationCache();
|
||||
BaseTermReadSvcImpl.clearOurLastResultsFromTranslationWithReverseCache();
|
||||
TermDeferredStorageSvcImpl deferredStorageSvc = AopTestUtils.getTargetObject(myTermDeferredStorageSvc);
|
||||
|
|
|
@ -6,6 +6,7 @@ import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
|||
import ca.uhn.fhir.jpa.search.LuceneSearchMappingFactory;
|
||||
import ca.uhn.fhir.jpa.util.DerbyTenSevenHapiFhirDialect;
|
||||
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
|
||||
import ca.uhn.fhir.validation.IValidatorModule;
|
||||
import ca.uhn.fhir.validation.ResultSeverityEnum;
|
||||
import ca.uhn.fhirtest.interceptor.PublicSecurityInterceptor;
|
||||
import org.apache.commons.dbcp2.BasicDataSource;
|
||||
|
@ -133,15 +134,16 @@ public class TestDstu2Config extends BaseJavaConfigDstu2 {
|
|||
|
||||
/**
|
||||
* Bean which validates incoming requests
|
||||
* @param theInstanceValidator
|
||||
*/
|
||||
@Bean
|
||||
@Lazy
|
||||
public RequestValidatingInterceptor requestValidatingInterceptor() {
|
||||
public RequestValidatingInterceptor requestValidatingInterceptor(IValidatorModule theInstanceValidator) {
|
||||
RequestValidatingInterceptor requestValidator = new RequestValidatingInterceptor();
|
||||
requestValidator.setFailOnSeverity(null);
|
||||
requestValidator.setAddResponseHeaderOnSeverity(null);
|
||||
requestValidator.setAddResponseOutcomeHeaderOnSeverity(ResultSeverityEnum.INFORMATION);
|
||||
requestValidator.addValidatorModule(instanceValidator());
|
||||
requestValidator.addValidatorModule(theInstanceValidator);
|
||||
requestValidator.setIgnoreValidatorExceptions(true);
|
||||
|
||||
return requestValidator;
|
||||
|
|
|
@ -18,7 +18,7 @@ spring:
|
|||
enabled: true
|
||||
hapi:
|
||||
fhir:
|
||||
version: dstu3
|
||||
version: DSTU3
|
||||
server:
|
||||
path: /fhir/*
|
||||
rest:
|
||||
|
|
|
@ -1,21 +1,27 @@
|
|||
package org.hl7.fhir.common.hapi.validation.support;
|
||||
|
||||
import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
|
||||
import ca.uhn.fhir.context.support.ConceptValidationOptions;
|
||||
import ca.uhn.fhir.context.support.IValidationSupport;
|
||||
import ca.uhn.fhir.context.support.ValidationSupportContext;
|
||||
import com.github.benmanes.caffeine.cache.Cache;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.hl7.fhir.instance.model.api.IBase;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.defaultIfBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.defaultString;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public class CachingValidationSupport extends BaseValidationSupportWrapper implements IValidationSupport {
|
||||
|
@ -96,6 +102,19 @@ public class CachingValidationSupport extends BaseValidationSupportWrapper imple
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public IValidationSupport.CodeValidationResult validateCodeInValueSet(ValidationSupportContext theValidationSupportContext, ConceptValidationOptions theValidationOptions, String theCodeSystem, String theCode, String theDisplay, @Nonnull IBaseResource theValueSet) {
|
||||
|
||||
BaseRuntimeChildDefinition urlChild = myCtx.getResourceDefinition(theValueSet).getChildByName("url");
|
||||
Optional<String> valueSetUrl = urlChild.getAccessor().getValues(theValueSet).stream().map(t -> ((IPrimitiveType<?>) t).getValueAsString()).filter(t->isNotBlank(t)).findFirst();
|
||||
if (valueSetUrl.isPresent()) {
|
||||
String key = "validateCodeInValueSet " + theValidationOptions.toString() + " " + defaultString(theCodeSystem, "(null)") + " " + defaultString(theCode, "(null)") + " " + defaultString(theDisplay, "(null)") + " " + valueSetUrl.get();
|
||||
return loadFromCache(myValidateCodeCache, key, t-> super.validateCodeInValueSet(theValidationSupportContext, theValidationOptions, theCodeSystem, theCode, theDisplay, theValueSet));
|
||||
}
|
||||
|
||||
return super.validateCodeInValueSet(theValidationSupportContext, theValidationOptions, theCodeSystem, theCode, theDisplay, theValueSet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateCaches() {
|
||||
myLookupCodeCache.invalidateAll();
|
||||
|
|
Loading…
Reference in New Issue