Work on removing validstion cache
This commit is contained in:
parent
d0761ea604
commit
fee0166800
|
@ -73,8 +73,10 @@ public class FhirResourceDaoDstu3<T extends IAnyResource> extends BaseHapiFhirRe
|
|||
|
||||
@Override
|
||||
public MethodOutcome validate(T theResource, IIdType theId, String theRawResource, EncodingEnum theEncoding, ValidationModeEnum theMode, String theProfile, RequestDetails theRequestDetails) {
|
||||
if (theRequestDetails != null) {
|
||||
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails, theResource, null, theId);
|
||||
notifyInterceptors(RestOperationTypeEnum.VALIDATE, requestDetails);
|
||||
}
|
||||
|
||||
if (theMode == ValidationModeEnum.DELETE) {
|
||||
if (theId == null || theId.hasIdPart() == false) {
|
||||
|
|
|
@ -20,19 +20,22 @@ package ca.uhn.fhir.jpa.dao.dstu3;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoCodeSystem;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoCodeSystem.LookupCodeResult;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet;
|
||||
import ca.uhn.fhir.jpa.util.LogicUtil;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.util.ElementUtil;
|
||||
import org.apache.commons.codec.binary.StringUtils;
|
||||
import org.hl7.fhir.dstu3.hapi.ctx.HapiWorkerContext;
|
||||
import org.hl7.fhir.dstu3.hapi.ctx.IValidationSupport;
|
||||
import org.hl7.fhir.dstu3.model.*;
|
||||
import org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.*;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetFilterComponent;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.FilterOperator;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionContainsComponent;
|
||||
import org.hl7.fhir.dstu3.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
|
@ -41,20 +44,18 @@ import org.slf4j.LoggerFactory;
|
|||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoCodeSystem;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoCodeSystem.LookupCodeResult;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet;
|
||||
import ca.uhn.fhir.jpa.util.LogicUtil;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.util.ElementUtil;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
public class FhirResourceDaoValueSetDstu3 extends FhirResourceDaoDstu3<ValueSet> implements IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> {
|
||||
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(FhirResourceDaoValueSetDstu3.class);
|
||||
@Autowired
|
||||
@Qualifier("myJpaValidationSupportChainDstu3")
|
||||
private IValidationSupport myValidationSupport;
|
||||
|
||||
@Autowired
|
||||
private IFhirResourceDaoCodeSystem<CodeSystem, Coding, CodeableConcept> myCodeSystemDao;
|
||||
|
||||
|
@ -69,21 +70,32 @@ public class FhirResourceDaoValueSetDstu3 extends FhirResourceDaoDstu3<ValueSet>
|
|||
validateIncludes("include", theSource.getCompose().getInclude());
|
||||
validateIncludes("exclude", theSource.getCompose().getExclude());
|
||||
|
||||
/*
|
||||
* If all of the code systems are supported by the HAPI FHIR terminology service, let's
|
||||
* use that as it's more efficient.
|
||||
*/
|
||||
|
||||
boolean allSystemsAreSuppportedByTerminologyService = true;
|
||||
for (ConceptSetComponent next : theSource.getCompose().getInclude()) {
|
||||
if (!myTerminologySvc.supportsSystem(next.getSystem())) {
|
||||
allSystemsAreSuppportedByTerminologyService = false;
|
||||
}
|
||||
}
|
||||
for (ConceptSetComponent next : theSource.getCompose().getExclude()) {
|
||||
if (!myTerminologySvc.supportsSystem(next.getSystem())) {
|
||||
allSystemsAreSuppportedByTerminologyService = false;
|
||||
}
|
||||
}
|
||||
if (allSystemsAreSuppportedByTerminologyService) {
|
||||
return (ValueSet) myTerminologySvc.expandValueSet(theSource);
|
||||
}
|
||||
|
||||
HapiWorkerContext workerContext = new HapiWorkerContext(getContext(), myValidationSupport);
|
||||
|
||||
ValueSetExpansionOutcome outcome = workerContext.expand(theSource, null);
|
||||
|
||||
ValueSet retVal = outcome.getValueset();
|
||||
retVal.setStatus(PublicationStatus.ACTIVE);
|
||||
|
||||
return retVal;
|
||||
|
||||
// ValueSetExpansionComponent expansion = outcome.getValueset().getExpansion();
|
||||
//
|
||||
// ValueSet retVal = new ValueSet();
|
||||
// retVal.getMeta().setLastUpdated(new Date());
|
||||
// retVal.setExpansion(expansion);
|
||||
// return retVal;
|
||||
}
|
||||
|
||||
private void validateIncludes(String name, List<ConceptSetComponent> listToValidate) {
|
||||
|
@ -242,9 +254,6 @@ public class FhirResourceDaoValueSetDstu3 extends FhirResourceDaoDstu3<ValueSet>
|
|||
|
||||
}
|
||||
|
||||
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(FhirResourceDaoValueSetDstu3.class);
|
||||
|
||||
private String toStringOrNull(IPrimitiveType<String> thePrimitive) {
|
||||
return thePrimitive != null ? thePrimitive.getValue() : null;
|
||||
}
|
||||
|
|
|
@ -63,8 +63,25 @@ public class FhirResourceDaoValueSetR4 extends FhirResourceDaoR4<ValueSet> imple
|
|||
|
||||
private ValueSet doExpand(ValueSet theSource) {
|
||||
|
||||
validateIncludes("include", theSource.getCompose().getInclude());
|
||||
validateIncludes("exclude", theSource.getCompose().getExclude());
|
||||
/*
|
||||
* If all of the code systems are supported by the HAPI FHIR terminology service, let's
|
||||
* use that as it's more efficient.
|
||||
*/
|
||||
|
||||
boolean allSystemsAreSuppportedByTerminologyService = true;
|
||||
for (ConceptSetComponent next : theSource.getCompose().getInclude()) {
|
||||
if (!myTerminologySvc.supportsSystem(next.getSystem())) {
|
||||
allSystemsAreSuppportedByTerminologyService = false;
|
||||
}
|
||||
}
|
||||
for (ConceptSetComponent next : theSource.getCompose().getExclude()) {
|
||||
if (!myTerminologySvc.supportsSystem(next.getSystem())) {
|
||||
allSystemsAreSuppportedByTerminologyService = false;
|
||||
}
|
||||
}
|
||||
if (allSystemsAreSuppportedByTerminologyService) {
|
||||
return myTerminologySvc.expandValueSet(theSource);
|
||||
}
|
||||
|
||||
HapiWorkerContext workerContext = new HapiWorkerContext(getContext(), myValidationSupport);
|
||||
|
||||
|
|
|
@ -52,8 +52,6 @@ import org.hibernate.search.jpa.FullTextEntityManager;
|
|||
import org.hibernate.search.jpa.FullTextQuery;
|
||||
import org.hibernate.search.query.dsl.BooleanJunction;
|
||||
import org.hibernate.search.query.dsl.QueryBuilder;
|
||||
import org.hibernate.search.query.dsl.TermMatchingContext;
|
||||
import org.hibernate.search.query.dsl.TermTermination;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.r4.model.CodeSystem;
|
||||
|
@ -84,6 +82,7 @@ import javax.persistence.TypedQuery;
|
|||
import javax.persistence.criteria.*;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
@ -141,8 +140,9 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
|||
|
||||
/**
|
||||
* @param theAdd If true, add the code. If false, remove the code.
|
||||
* @param theCodeCounter
|
||||
*/
|
||||
private void addCodeIfNotAlreadyAdded(String theCodeSystem, ValueSet.ValueSetExpansionComponent theExpansionComponent, Set<String> theAddedCodes, TermConcept theConcept, boolean theAdd) {
|
||||
private void addCodeIfNotAlreadyAdded(String theCodeSystem, ValueSet.ValueSetExpansionComponent theExpansionComponent, Set<String> theAddedCodes, TermConcept theConcept, boolean theAdd, AtomicInteger theCodeCounter) {
|
||||
String code = theConcept.getCode();
|
||||
if (theAdd && theAddedCodes.add(code)) {
|
||||
ValueSet.ValueSetExpansionContainsComponent contains = theExpansionComponent.addContains();
|
||||
|
@ -158,10 +158,13 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
|||
.setCode(nextDesignation.getUseCode())
|
||||
.setDisplay(nextDesignation.getUseDisplay());
|
||||
}
|
||||
|
||||
theCodeCounter.incrementAndGet();
|
||||
}
|
||||
|
||||
if (!theAdd && theAddedCodes.remove(code)) {
|
||||
removeCodeFromExpansion(theCodeSystem, code, theExpansionComponent);
|
||||
theCodeCounter.decrementAndGet();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -412,22 +415,32 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
|||
@Override
|
||||
@Transactional(propagation = Propagation.REQUIRED)
|
||||
public ValueSet expandValueSet(ValueSet theValueSetToExpand) {
|
||||
|
||||
ValueSet.ValueSetExpansionComponent expansionComponent = new ValueSet.ValueSetExpansionComponent();
|
||||
expansionComponent.setIdentifier(UUID.randomUUID().toString());
|
||||
expansionComponent.setTimestamp(new Date());
|
||||
|
||||
Set<String> addedCodes = new HashSet<>();
|
||||
AtomicInteger codeCounter = new AtomicInteger(0);
|
||||
|
||||
// Handle includes
|
||||
ourLog.debug("Handling includes");
|
||||
for (ValueSet.ConceptSetComponent include : theValueSetToExpand.getCompose().getInclude()) {
|
||||
boolean add = true;
|
||||
expandValueSetHandleIncludeOrExclude(expansionComponent, addedCodes, include, add);
|
||||
expandValueSetHandleIncludeOrExclude(expansionComponent, addedCodes, include, add, codeCounter);
|
||||
}
|
||||
|
||||
// Handle excludes
|
||||
ourLog.debug("Handling excludes");
|
||||
for (ValueSet.ConceptSetComponent include : theValueSetToExpand.getCompose().getExclude()) {
|
||||
boolean add = false;
|
||||
expandValueSetHandleIncludeOrExclude(expansionComponent, addedCodes, include, add);
|
||||
expandValueSetHandleIncludeOrExclude(expansionComponent, addedCodes, include, add, codeCounter);
|
||||
}
|
||||
|
||||
expansionComponent.setTotal(codeCounter.get());
|
||||
|
||||
ValueSet valueSet = new ValueSet();
|
||||
valueSet.setCompose(theValueSetToExpand.getCompose());
|
||||
valueSet.setExpansion(expansionComponent);
|
||||
return valueSet;
|
||||
}
|
||||
|
@ -445,10 +458,10 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
|||
return retVal;
|
||||
}
|
||||
|
||||
public void expandValueSetHandleIncludeOrExclude(ValueSet.ValueSetExpansionComponent theExpansionComponent, Set<String> theAddedCodes, ValueSet.ConceptSetComponent include, boolean theAdd) {
|
||||
String system = include.getSystem();
|
||||
public void expandValueSetHandleIncludeOrExclude(ValueSet.ValueSetExpansionComponent theExpansionComponent, Set<String> theAddedCodes, ValueSet.ConceptSetComponent theInclude, boolean theAdd, AtomicInteger theCodeCounter) {
|
||||
String system = theInclude.getSystem();
|
||||
ourLog.info("Starting {} expansion around code system: {}", (theAdd ? "inclusion" : "exclusion"), system);
|
||||
if (isNotBlank(system)) {
|
||||
ourLog.info("Starting expansion around code system: {}", system);
|
||||
|
||||
TermCodeSystem cs = myCodeSystemDao.findByCodeSystemUri(system);
|
||||
if (cs != null) {
|
||||
|
@ -463,9 +476,9 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
|||
* Filters
|
||||
*/
|
||||
|
||||
if (include.getFilter().size() > 0) {
|
||||
if (theInclude.getFilter().size() > 0) {
|
||||
|
||||
for (ValueSet.ConceptSetFilterComponent nextFilter : include.getFilter()) {
|
||||
for (ValueSet.ConceptSetFilterComponent nextFilter : theInclude.getFilter()) {
|
||||
if (isBlank(nextFilter.getValue()) && nextFilter.getOp() == null && isBlank(nextFilter.getProperty())) {
|
||||
continue;
|
||||
}
|
||||
|
@ -542,13 +555,13 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
|||
* Include Concepts
|
||||
*/
|
||||
|
||||
List<Term> codes = include
|
||||
List<Term> codes = theInclude
|
||||
.getConcept()
|
||||
.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.map(ValueSet.ConceptReferenceComponent::getCode)
|
||||
.filter(StringUtils::isNotBlank)
|
||||
.map(t->new Term("myCode", t))
|
||||
.map(t -> new Term("myCode", t))
|
||||
.collect(Collectors.toList());
|
||||
if (codes.size() > 0) {
|
||||
MultiPhraseQuery query = new MultiPhraseQuery();
|
||||
|
@ -564,19 +577,25 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
|||
*/
|
||||
|
||||
FullTextQuery jpaQuery = em.createFullTextQuery(luceneQuery, TermConcept.class);
|
||||
jpaQuery.setMaxResults(1000);
|
||||
int maxResult = 50000;
|
||||
jpaQuery.setMaxResults(maxResult);
|
||||
|
||||
StopWatch sw = new StopWatch();
|
||||
AtomicInteger count = new AtomicInteger(0);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<TermConcept> result = jpaQuery.getResultList();
|
||||
|
||||
ourLog.info("Expansion completed in {}ms", sw.getMillis());
|
||||
|
||||
for (TermConcept nextConcept : result) {
|
||||
addCodeIfNotAlreadyAdded(system, theExpansionComponent, theAddedCodes, nextConcept, theAdd);
|
||||
for (Object next : jpaQuery.getResultList()) {
|
||||
count.incrementAndGet();
|
||||
TermConcept concept = (TermConcept) next;
|
||||
addCodeIfNotAlreadyAdded(system, theExpansionComponent, theAddedCodes, concept, theAdd, theCodeCounter);
|
||||
}
|
||||
|
||||
|
||||
if (maxResult == count.get()) {
|
||||
throw new InternalErrorException("Expansion fragment produced too many (>= " + maxResult + ") results");
|
||||
}
|
||||
|
||||
ourLog.info("Expansion for {} produced {} results in {}ms", (theAdd ? "inclusion" : "exclusion"), count, sw.getMillis());
|
||||
|
||||
} else {
|
||||
// No codesystem matching the URL found in the database
|
||||
|
||||
|
@ -585,8 +604,8 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
|||
throw new InvalidRequestException("Unknown code system: " + system);
|
||||
}
|
||||
|
||||
if (include.getConcept().isEmpty() == false) {
|
||||
for (ValueSet.ConceptReferenceComponent next : include.getConcept()) {
|
||||
if (theInclude.getConcept().isEmpty() == false) {
|
||||
for (ValueSet.ConceptReferenceComponent next : theInclude.getConcept()) {
|
||||
String nextCode = next.getCode();
|
||||
if (isNotBlank(nextCode) && !theAddedCodes.contains(nextCode)) {
|
||||
CodeSystem.ConceptDefinitionComponent code = findCode(codeSystemFromContext.getConcept(), nextCode);
|
||||
|
|
|
@ -21,6 +21,7 @@ package ca.uhn.fhir.jpa.term;
|
|||
*/
|
||||
|
||||
import org.hl7.fhir.instance.hapi.validation.IValidationSupport;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.r4.model.CodeSystem;
|
||||
import org.hl7.fhir.r4.model.ConceptMap;
|
||||
|
@ -80,6 +81,11 @@ public class HapiTerminologySvcDstu2 extends BaseHapiTerminologySvcImpl {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBaseResource expandValueSet(IBaseResource theValueSetToExpand) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<VersionIndependentConcept> expandValueSet(String theValueSet) {
|
||||
throw new UnsupportedOperationException();
|
||||
|
|
|
@ -166,6 +166,20 @@ public class HapiTerminologySvcDstu3 extends BaseHapiTerminologySvcImpl implemen
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBaseResource expandValueSet(IBaseResource theInput) {
|
||||
ValueSet valueSetToExpand = (ValueSet) theInput;
|
||||
|
||||
try {
|
||||
org.hl7.fhir.r4.model.ValueSet valueSetToExpandR4;
|
||||
valueSetToExpandR4 = VersionConvertor_30_40.convertValueSet(valueSetToExpand);
|
||||
org.hl7.fhir.r4.model.ValueSet expandedR4 = super.expandValueSet(valueSetToExpandR4);
|
||||
return VersionConvertor_30_40.convertValueSet(expandedR4);
|
||||
} catch (FHIRException e) {
|
||||
throw new InternalErrorException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<VersionIndependentConcept> expandValueSet(String theValueSet) {
|
||||
ValueSet vs = myValidationSupport.fetchResource(myContext, ValueSet.class, theValueSet);
|
||||
|
|
|
@ -134,6 +134,13 @@ public class HapiTerminologySvcR4 extends BaseHapiTerminologySvcImpl implements
|
|||
return expandValueSetAndReturnVersionIndependentConcepts(vs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBaseResource expandValueSet(IBaseResource theInput) {
|
||||
ValueSet valueSetToExpand = (ValueSet) theInput;
|
||||
return super.expandValueSet(valueSetToExpand);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ValueSetExpansionComponent expandValueSet(FhirContext theContext, ConceptSetComponent theInclude) {
|
||||
ValueSet valueSetToExpand = new ValueSet();
|
||||
|
|
|
@ -2,6 +2,7 @@ package ca.uhn.fhir.jpa.term;
|
|||
|
||||
import ca.uhn.fhir.jpa.entity.*;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.r4.model.ConceptMap;
|
||||
import org.hl7.fhir.r4.model.ValueSet;
|
||||
|
@ -35,6 +36,11 @@ public interface IHapiTerminologySvc {
|
|||
|
||||
ValueSet expandValueSet(ValueSet theValueSetToExpand);
|
||||
|
||||
/**
|
||||
* Version independent
|
||||
*/
|
||||
IBaseResource expandValueSet(IBaseResource theValueSetToExpand);
|
||||
|
||||
List<VersionIndependentConcept> expandValueSet(String theValueSet);
|
||||
|
||||
TermConcept findCode(String theCodeSystem, String theCode);
|
||||
|
|
|
@ -28,6 +28,48 @@ public class FhirResourceDaoDstu3ValidateTest extends BaseJpaDstu3Test {
|
|||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateChangedQuestionnaire() {
|
||||
Questionnaire q = new Questionnaire();
|
||||
q.setId("QUEST");
|
||||
q.addItem().setLinkId("A").setType(Questionnaire.QuestionnaireItemType.STRING).setRequired(true);
|
||||
myQuestionnaireDao.update(q);
|
||||
|
||||
try {
|
||||
QuestionnaireResponse qr = new QuestionnaireResponse();
|
||||
qr.setStatus(QuestionnaireResponse.QuestionnaireResponseStatus.COMPLETED);
|
||||
qr.getQuestionnaire().setReference("Questionnaire/QUEST");
|
||||
qr.addItem().setLinkId("A").addAnswer().setValue(new StringType("AAA"));
|
||||
|
||||
MethodOutcome results = myQuestionnaireResponseDao.validate(qr, null, null, null, null, null, null);
|
||||
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(results.getOperationOutcome()));
|
||||
} catch (PreconditionFailedException e) {
|
||||
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(e.getOperationOutcome()));
|
||||
fail(e.toString());
|
||||
}
|
||||
|
||||
|
||||
q = new Questionnaire();
|
||||
q.setId("QUEST");
|
||||
q.addItem().setLinkId("B").setType(Questionnaire.QuestionnaireItemType.STRING).setRequired(true);
|
||||
myQuestionnaireDao.update(q);
|
||||
|
||||
try {
|
||||
QuestionnaireResponse qr = new QuestionnaireResponse();
|
||||
qr.setStatus(QuestionnaireResponse.QuestionnaireResponseStatus.COMPLETED);
|
||||
qr.getQuestionnaire().setReference("Questionnaire/QUEST");
|
||||
qr.addItem().setLinkId("A").addAnswer().setValue(new StringType("AAA"));
|
||||
|
||||
MethodOutcome results = myQuestionnaireResponseDao.validate(qr, null, null, null, null, null, null);
|
||||
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(results.getOperationOutcome()));
|
||||
fail();
|
||||
} catch (PreconditionFailedException e) {
|
||||
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(e.getOperationOutcome()));
|
||||
// good
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateStructureDefinition() throws Exception {
|
||||
String input = IOUtils.toString(getClass().getResourceAsStream("/sd-david-dhtest7.json"), StandardCharsets.UTF_8);
|
||||
|
|
|
@ -32,6 +32,8 @@ import org.springframework.transaction.annotation.Transactional;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static ca.uhn.fhir.jpa.dao.dstu3.FhirResourceDaoDstu3TerminologyTest.URL_MY_CODE_SYSTEM;
|
||||
import static ca.uhn.fhir.jpa.dao.dstu3.FhirResourceDaoDstu3TerminologyTest.URL_MY_VALUE_SET;
|
||||
|
@ -96,6 +98,39 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
|
|||
createLocalVs(codeSystem);
|
||||
}
|
||||
|
||||
|
||||
public void createLoincSystemWithSomeCodes() {
|
||||
runInTransaction(() -> {
|
||||
CodeSystem codeSystem = new CodeSystem();
|
||||
codeSystem.setUrl(CS_URL);
|
||||
codeSystem.setContent(CodeSystemContentMode.NOTPRESENT);
|
||||
IIdType id = myCodeSystemDao.create(codeSystem, mySrd).getId().toUnqualified();
|
||||
|
||||
ResourceTable table = myResourceTableDao.findById(id.getIdPartAsLong()).orElseThrow(IllegalArgumentException::new);
|
||||
|
||||
TermCodeSystemVersion cs = new TermCodeSystemVersion();
|
||||
cs.setResource(table);
|
||||
|
||||
TermConcept code;
|
||||
code = new TermConcept(cs, "50015-7");
|
||||
code.addPropertyString("SYSTEM", "Bld/Bone mar^Donor");
|
||||
cs.getConcepts().add(code);
|
||||
|
||||
code = new TermConcept(cs, "43343-3");
|
||||
code.addPropertyString("SYSTEM", "Ser");
|
||||
code.addPropertyString("HELLO", "12345-1");
|
||||
cs.getConcepts().add(code);
|
||||
|
||||
code = new TermConcept(cs, "43343-4");
|
||||
code.addPropertyString("SYSTEM", "Ser");
|
||||
code.addPropertyString("HELLO", "12345-2");
|
||||
cs.getConcepts().add(code);
|
||||
|
||||
myTermSvc.storeNewCodeSystemVersion(table.getId(), CS_URL, "SYSTEM NAME", cs);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private void createLocalVs(CodeSystem codeSystem) {
|
||||
myLocalVs = new ValueSet();
|
||||
myLocalVs.setUrl(URL_MY_VALUE_SET);
|
||||
|
@ -132,6 +167,71 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
|
|||
myLocalValueSetId = myValueSetDao.create(myLocalVs, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testExpandValueSetPropertySearchWithRegexExcludeUsingOr() {
|
||||
createLoincSystemWithSomeCodes();
|
||||
|
||||
List<String> codes;
|
||||
ValueSet vs;
|
||||
ValueSet outcome;
|
||||
ValueSet.ConceptSetComponent exclude;
|
||||
|
||||
// Include
|
||||
vs = new ValueSet();
|
||||
vs.getCompose()
|
||||
.addInclude()
|
||||
.setSystem(CS_URL);
|
||||
|
||||
|
||||
exclude = vs.getCompose().addExclude();
|
||||
exclude.setSystem(CS_URL);
|
||||
exclude
|
||||
.addFilter()
|
||||
.setProperty("HELLO")
|
||||
.setOp(ValueSet.FilterOperator.REGEX)
|
||||
.setValue("12345-1|12345-2");
|
||||
|
||||
IIdType vsId = ourClient.create().resource(vs).execute().getId();
|
||||
outcome = (ValueSet) ourClient.operation().onInstance(vsId).named("expand").withNoParameters(Parameters.class).execute().getParameter().get(0).getResource();
|
||||
codes = toCodesContains(outcome.getExpansion().getContains());
|
||||
ourLog.info("** Got codes: {}", codes);
|
||||
assertThat(codes, containsInAnyOrder("50015-7"));
|
||||
|
||||
|
||||
assertEquals(1, outcome.getCompose().getInclude().size());
|
||||
assertEquals(1, outcome.getCompose().getExclude().size());
|
||||
assertEquals(1, outcome.getExpansion().getTotal());
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testExpandValueSetPropertySearchWithRegexExcludeNoFilter() {
|
||||
createLoincSystemWithSomeCodes();
|
||||
|
||||
List<String> codes;
|
||||
ValueSet vs;
|
||||
ValueSet outcome;
|
||||
ValueSet.ConceptSetComponent exclude;
|
||||
|
||||
// Include
|
||||
vs = new ValueSet();
|
||||
vs.getCompose()
|
||||
.addInclude()
|
||||
.setSystem(CS_URL);
|
||||
|
||||
|
||||
exclude = vs.getCompose().addExclude();
|
||||
exclude.setSystem(CS_URL);
|
||||
|
||||
IIdType vsId = ourClient.create().resource(vs).execute().getId();
|
||||
outcome = (ValueSet) ourClient.operation().onInstance(vsId).named("expand").withNoParameters(Parameters.class).execute().getParameter().get(0).getResource();
|
||||
codes = toCodesContains(outcome.getExpansion().getContains());
|
||||
assertThat(codes, empty());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testExpandById() throws IOException {
|
||||
//@formatter:off
|
||||
|
@ -611,4 +711,15 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
|
|||
return codeSystem;
|
||||
}
|
||||
|
||||
|
||||
public static List<String> toCodesContains(List<ValueSet.ValueSetExpansionContainsComponent> theContains) {
|
||||
List<String> retVal = new ArrayList<>();
|
||||
|
||||
for (ValueSet.ValueSetExpansionContainsComponent next : theContains) {
|
||||
retVal.add(next.getCode());
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -591,7 +591,7 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
|
|||
}
|
||||
}
|
||||
|
||||
private List<String> toCodesContains(List<ValueSet.ValueSetExpansionContainsComponent> theContains) {
|
||||
public static List<String> toCodesContains(List<ValueSet.ValueSetExpansionContainsComponent> theContains) {
|
||||
List<String> retVal = new ArrayList<>();
|
||||
|
||||
for (ValueSet.ValueSetExpansionContainsComponent next : theContains) {
|
||||
|
|
|
@ -168,6 +168,14 @@
|
|||
</dependency>
|
||||
-->
|
||||
|
||||
<!-- Used by the validator -->
|
||||
<dependency>
|
||||
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||
<artifactId>caffeine</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- Testing -->
|
||||
<dependency>
|
||||
<groupId>org.xmlunit</groupId>
|
||||
|
|
|
@ -4,6 +4,8 @@ import ca.uhn.fhir.context.FhirContext;
|
|||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.util.CoverageIgnore;
|
||||
import com.github.benmanes.caffeine.cache.Cache;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.hl7.fhir.dstu3.context.IWorkerContext;
|
||||
import org.hl7.fhir.dstu3.formats.IParser;
|
||||
|
@ -22,13 +24,15 @@ import org.hl7.fhir.exceptions.FHIRException;
|
|||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
public final class HapiWorkerContext implements IWorkerContext, ValueSetExpander, ValueSetExpanderFactory {
|
||||
private final FhirContext myCtx;
|
||||
private Map<String, Resource> myFetchedResourceCache = new HashMap<String, Resource>();
|
||||
private final Cache<String, Resource> myFetchedResourceCache;
|
||||
|
||||
private IValidationSupport myValidationSupport;
|
||||
private ExpansionProfile myExpansionProfile;
|
||||
|
||||
|
@ -37,6 +41,7 @@ public final class HapiWorkerContext implements IWorkerContext, ValueSetExpander
|
|||
Validate.notNull(theValidationSupport, "theValidationSupport must not be null");
|
||||
myCtx = theCtx;
|
||||
myValidationSupport = theValidationSupport;
|
||||
myFetchedResourceCache = Caffeine.newBuilder().expireAfterWrite(10, TimeUnit.SECONDS).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -92,13 +97,9 @@ public final class HapiWorkerContext implements IWorkerContext, ValueSetExpander
|
|||
return null;
|
||||
} else {
|
||||
@SuppressWarnings("unchecked")
|
||||
T retVal = (T) myFetchedResourceCache.get(theUri);
|
||||
if (retVal == null) {
|
||||
retVal = myValidationSupport.fetchResource(myCtx, theClass, theUri);
|
||||
if (retVal != null) {
|
||||
myFetchedResourceCache.put(theUri, retVal);
|
||||
}
|
||||
}
|
||||
T retVal = (T) myFetchedResourceCache.get(theUri, t->{
|
||||
return myValidationSupport.fetchResource(myCtx, theClass, theUri);
|
||||
});
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,6 +50,13 @@
|
|||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- Used by the validator -->
|
||||
<dependency>
|
||||
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||
<artifactId>caffeine</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!--
|
||||
Test dependencies on other optional parts of HAPI
|
||||
-->
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
package org.hl7.fhir.r4.hapi.ctx;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.util.CoverageIgnore;
|
||||
import com.github.benmanes.caffeine.cache.Cache;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.fhir.ucum.UcumService;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
|
@ -28,13 +29,14 @@ import org.hl7.fhir.utilities.TranslationServices;
|
|||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
public final class HapiWorkerContext implements IWorkerContext, ValueSetExpander, ValueSetExpanderFactory {
|
||||
private final FhirContext myCtx;
|
||||
private Map<String, Resource> myFetchedResourceCache = new HashMap<String, Resource>();
|
||||
private final Cache<String, Resource> myFetchedResourceCache;
|
||||
private IValidationSupport myValidationSupport;
|
||||
private ExpansionProfile myExpansionProfile;
|
||||
|
||||
|
@ -43,6 +45,7 @@ public final class HapiWorkerContext implements IWorkerContext, ValueSetExpander
|
|||
Validate.notNull(theValidationSupport, "theValidationSupport must not be null");
|
||||
myCtx = theCtx;
|
||||
myValidationSupport = theValidationSupport;
|
||||
myFetchedResourceCache = Caffeine.newBuilder().expireAfterWrite(10, TimeUnit.SECONDS).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -338,13 +341,9 @@ public final class HapiWorkerContext implements IWorkerContext, ValueSetExpander
|
|||
return null;
|
||||
} else {
|
||||
@SuppressWarnings("unchecked")
|
||||
T retVal = (T) myFetchedResourceCache.get(theUri);
|
||||
if (retVal == null) {
|
||||
retVal = myValidationSupport.fetchResource(myCtx, theClass, theUri);
|
||||
if (retVal != null) {
|
||||
myFetchedResourceCache.put(theUri, (Resource) retVal);
|
||||
}
|
||||
}
|
||||
T retVal = (T) myFetchedResourceCache.get(theUri, t -> {
|
||||
return myValidationSupport.fetchResource(myCtx, theClass, theUri);
|
||||
});
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue