Merge branch 'master' of github.com:jamesagnew/hapi-fhir
This commit is contained in:
commit
1ef70a0fca
|
@ -127,11 +127,5 @@ ca.uhn.fhir.jpa.term.BaseHapiTerminologySvcImpl.cannotCreateDuplicateCodeSystemU
|
|||
ca.uhn.fhir.jpa.term.BaseHapiTerminologySvcImpl.cannotCreateDuplicateConceptMapUrl=Can not create multiple ConceptMap resources with ConceptMap.url "{0}", already have one with resource ID: {1}
|
||||
ca.uhn.fhir.jpa.term.BaseHapiTerminologySvcImpl.cannotCreateDuplicateValueSetUrl=Can not create multiple ValueSet resources with ValueSet.url "{0}", already have one with resource ID: {1}
|
||||
ca.uhn.fhir.jpa.term.BaseHapiTerminologySvcImpl.expansionTooLarge=Expansion of ValueSet produced too many codes (maximum {0}) - Operation aborted!
|
||||
ca.uhn.fhir.jpa.term.BaseHapiTerminologySvcImpl.valueSetNotReadyForExpand=ValueSet is not ready for operation $expand; current status: {0} | {1}
|
||||
|
||||
ca.uhn.fhir.jpa.util.jsonpatch.JsonPatchUtils.failedToApplyPatch=Failed to apply JSON patch to {0}: {1}
|
||||
|
||||
ca.uhn.fhir.jpa.entity.TermValueSetPreExpansionStatusEnum.notExpanded=The ValueSet is waiting to be picked up and pre-expanded by a scheduled task.
|
||||
ca.uhn.fhir.jpa.entity.TermValueSetPreExpansionStatusEnum.expansionInProgress=The ValueSet has been picked up by a scheduled task and pre-expansion is in progress.
|
||||
ca.uhn.fhir.jpa.entity.TermValueSetPreExpansionStatusEnum.expanded=The ValueSet has been picked up by a scheduled task and pre-expansion is complete.
|
||||
ca.uhn.fhir.jpa.entity.TermValueSetPreExpansionStatusEnum.failedToExpand=The ValueSet has been picked up by a scheduled task and pre-expansion has failed.
|
||||
|
|
|
@ -47,8 +47,8 @@ public interface ITermValueSetConceptDao extends JpaRepository<TermValueSetConce
|
|||
Optional<TermValueSetConcept> findByTermValueSetIdSystemAndCode(@Param("pid") Long theValueSetId, @Param("system_url") String theSystem, @Param("codeval") String theCode);
|
||||
|
||||
@Query("SELECT vsc FROM TermValueSetConcept vsc WHERE vsc.myValueSet.myResourcePid = :resource_pid AND vsc.myCode = :codeval")
|
||||
List<TermValueSetConcept> findOneByValueSetIdAndCode(@Param("resource_pid") Long theValueSetId, @Param("codeval") String theCode);
|
||||
List<TermValueSetConcept> findByValueSetResourcePidAndCode(@Param("resource_pid") Long theValueSetId, @Param("codeval") String theCode);
|
||||
|
||||
@Query("SELECT vsc FROM TermValueSetConcept vsc WHERE vsc.myValueSet.myResourcePid = :resource_pid AND vsc.mySystem = :system_url AND vsc.myCode = :codeval")
|
||||
List<TermValueSetConcept> findOneByValueSetIdSystemAndCode(@Param("resource_pid") Long theValueSetId, @Param("system_url") String theSystem, @Param("codeval") String theCode);
|
||||
Optional<TermValueSetConcept> findByValueSetResourcePidSystemAndCode(@Param("resource_pid") Long theValueSetId, @Param("system_url") String theSystem, @Param("codeval") String theCode);
|
||||
}
|
||||
|
|
|
@ -331,7 +331,7 @@ public class FhirResourceDaoValueSetDstu3 extends FhirResourceDaoDstu3<ValueSet>
|
|||
|
||||
if (vs != null) {
|
||||
ValidateCodeResult result;
|
||||
if (myDaoConfig.isPreExpandValueSetsExperimental()) {
|
||||
if (myDaoConfig.isPreExpandValueSetsExperimental() && myTerminologySvc.isValueSetPreExpandedForCodeValidation(vs)) {
|
||||
result = myTerminologySvc.validateCodeIsInPreExpandedValueSet(vs, toStringOrNull(theSystem), toStringOrNull(theCode), toStringOrNull(theDisplay), theCoding, theCodeableConcept);
|
||||
} else {
|
||||
ValueSet expansion = doExpand(vs);
|
||||
|
|
|
@ -327,7 +327,7 @@ public class FhirResourceDaoValueSetR4 extends FhirResourceDaoR4<ValueSet> imple
|
|||
|
||||
if (vs != null) {
|
||||
ValidateCodeResult result;
|
||||
if (myDaoConfig.isPreExpandValueSetsExperimental()) {
|
||||
if (myDaoConfig.isPreExpandValueSetsExperimental() && myTerminologySvc.isValueSetPreExpandedForCodeValidation(vs)) {
|
||||
result = myTerminologySvc.validateCodeIsInPreExpandedValueSet(vs, toStringOrNull(theSystem), toStringOrNull(theCode), toStringOrNull(theDisplay), theCoding, theCodeableConcept);
|
||||
} else {
|
||||
ValueSet expansion = doExpand(vs);
|
||||
|
|
|
@ -333,7 +333,7 @@ public class FhirResourceDaoValueSetR5 extends FhirResourceDaoR5<ValueSet> imple
|
|||
|
||||
if (vs != null) {
|
||||
ValidateCodeResult result;
|
||||
if (myDaoConfig.isPreExpandValueSetsExperimental()) {
|
||||
if (myDaoConfig.isPreExpandValueSetsExperimental() && myTerminologySvc.isValueSetPreExpandedForCodeValidation(vs)) {
|
||||
result = myTerminologySvc.validateCodeIsInPreExpandedValueSet(vs, toStringOrNull(theSystem), toStringOrNull(theCode), toStringOrNull(theDisplay), theCoding, theCodeableConcept);
|
||||
} else {
|
||||
ValueSet expansion = doExpand(vs);
|
||||
|
|
|
@ -29,26 +29,32 @@ import java.util.Map;
|
|||
* an expanded ValueSet has its included concepts stored in the terminology tables as well.
|
||||
*/
|
||||
public enum TermValueSetPreExpansionStatusEnum {
|
||||
/**
|
||||
/*
|
||||
* Sorting agnostic.
|
||||
*/
|
||||
|
||||
NOT_EXPANDED("notExpanded"),
|
||||
EXPANSION_IN_PROGRESS("expansionInProgress"),
|
||||
EXPANDED("expanded"),
|
||||
FAILED_TO_EXPAND("failedToExpand");
|
||||
NOT_EXPANDED("notExpanded", "The ValueSet is waiting to be picked up and pre-expanded by a scheduled task."),
|
||||
EXPANSION_IN_PROGRESS("expansionInProgress", "The ValueSet has been picked up by a scheduled task and pre-expansion is in progress."),
|
||||
EXPANDED("expanded", "The ValueSet has been picked up by a scheduled task and pre-expansion is complete."),
|
||||
FAILED_TO_EXPAND("failedToExpand", "The ValueSet has been picked up by a scheduled task and pre-expansion has failed.");
|
||||
|
||||
private static Map<String, TermValueSetPreExpansionStatusEnum> ourValues;
|
||||
private String myCode;
|
||||
private String myDescription;
|
||||
|
||||
TermValueSetPreExpansionStatusEnum(String theCode) {
|
||||
TermValueSetPreExpansionStatusEnum(String theCode, String theDescription) {
|
||||
myCode = theCode;
|
||||
myDescription = theDescription;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return myCode;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return myDescription;
|
||||
}
|
||||
|
||||
public static TermValueSetPreExpansionStatusEnum fromCode(String theCode) {
|
||||
if (ourValues == null) {
|
||||
HashMap<String, TermValueSetPreExpansionStatusEnum> values = new HashMap<String, TermValueSetPreExpansionStatusEnum>();
|
||||
|
|
|
@ -55,6 +55,7 @@ import org.hibernate.search.query.dsl.BooleanJunction;
|
|||
import org.hibernate.search.query.dsl.QueryBuilder;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.instance.model.api.IBaseCoding;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
|
@ -145,6 +146,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
|||
@Autowired
|
||||
private PlatformTransactionManager myTransactionMgr;
|
||||
private IFhirResourceDaoCodeSystem<?, ?, ?> myCodeSystemResourceDao;
|
||||
private IFhirResourceDaoValueSet<?, ?, ?> myValueSetResourceDao;
|
||||
private Cache<TranslationQuery, List<TermConceptMapGroupElementTarget>> myTranslationCache;
|
||||
private Cache<TranslationQuery, List<TermConceptMapGroupElement>> myTranslationWithReverseCache;
|
||||
private int myFetchSize = DEFAULT_FETCH_SIZE;
|
||||
|
@ -486,7 +488,8 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
|||
|
||||
Optional<TermValueSet> optionalTermValueSet;
|
||||
if (theValueSetToExpand.hasId()) {
|
||||
optionalTermValueSet = myValueSetDao.findByResourcePid(theValueSetToExpand.getIdElement().getIdPartAsLong());
|
||||
Long valueSetResourcePid = getValueSetResourcePid(theValueSetToExpand.getIdElement());
|
||||
optionalTermValueSet = myValueSetDao.findByResourcePid(valueSetResourcePid);
|
||||
} else if (theValueSetToExpand.hasUrl()) {
|
||||
optionalTermValueSet = myValueSetDao.findByUrl(theValueSetToExpand.getUrl());
|
||||
} else {
|
||||
|
@ -494,12 +497,18 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
|||
}
|
||||
|
||||
if (!optionalTermValueSet.isPresent()) {
|
||||
throw new InvalidRequestException("ValueSet is not present in terminology tables: " + theValueSetToExpand.getUrl());
|
||||
ourLog.warn("ValueSet is not present in terminology tables. Will perform in-memory expansion without parameters. Will schedule this ValueSet for pre-expansion. {}", getValueSetInfo(theValueSetToExpand));
|
||||
myDeferredValueSets.add(theValueSetToExpand);
|
||||
return expandValueSet(theValueSetToExpand); // In-memory expansion.
|
||||
}
|
||||
|
||||
TermValueSet termValueSet = optionalTermValueSet.get();
|
||||
|
||||
validatePreExpansionStatusOfValueSetOrThrowException(termValueSet.getExpansionStatus());
|
||||
if (termValueSet.getExpansionStatus() != TermValueSetPreExpansionStatusEnum.EXPANDED) {
|
||||
ourLog.warn("{} is present in terminology tables but not ready for persistence-backed invocation of operation $expand. Will perform in-memory expansion without parameters. Current status: {} | {}",
|
||||
getValueSetInfo(theValueSetToExpand), termValueSet.getExpansionStatus().name(), termValueSet.getExpansionStatus().getDescription());
|
||||
return expandValueSet(theValueSetToExpand); // In-memory expansion.
|
||||
}
|
||||
|
||||
ValueSet.ValueSetExpansionComponent expansionComponent = new ValueSet.ValueSetExpansionComponent();
|
||||
expansionComponent.setIdentifier(UUID.randomUUID().toString());
|
||||
|
@ -514,20 +523,6 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
|||
return valueSet;
|
||||
}
|
||||
|
||||
private void validatePreExpansionStatusOfValueSetOrThrowException(TermValueSetPreExpansionStatusEnum thePreExpansionStatus) {
|
||||
if (TermValueSetPreExpansionStatusEnum.EXPANDED != thePreExpansionStatus) {
|
||||
String statusMsg = myContext.getLocalizer().getMessage(
|
||||
TermValueSetPreExpansionStatusEnum.class,
|
||||
thePreExpansionStatus.getCode());
|
||||
String msg = myContext.getLocalizer().getMessage(
|
||||
BaseHapiTerminologySvcImpl.class,
|
||||
"valueSetNotReadyForExpand",
|
||||
thePreExpansionStatus.name(),
|
||||
statusMsg);
|
||||
throw new UnprocessableEntityException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
private void populateExpansionComponent(ValueSet.ValueSetExpansionComponent theExpansionComponent, TermValueSet theTermValueSet, int theOffset, int theCount) {
|
||||
int total = myValueSetConceptDao.countByTermValueSetId(theTermValueSet.getId());
|
||||
theExpansionComponent.setTotal(total);
|
||||
|
@ -960,28 +955,49 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValueSetPreExpandedForCodeValidation(ValueSet theValueSet) {
|
||||
Long valueSetResourcePid = getValueSetResourcePid(theValueSet.getIdElement());
|
||||
Optional<TermValueSet> optionalTermValueSet = myValueSetDao.findByResourcePid(valueSetResourcePid);
|
||||
|
||||
if (!optionalTermValueSet.isPresent()) {
|
||||
ourLog.warn("ValueSet is not present in terminology tables. Will perform in-memory code validation. Will schedule this ValueSet for pre-expansion. {}", getValueSetInfo(theValueSet));
|
||||
myDeferredValueSets.add(theValueSet);
|
||||
return false;
|
||||
}
|
||||
|
||||
TermValueSet termValueSet = optionalTermValueSet.get();
|
||||
|
||||
if (termValueSet.getExpansionStatus() != TermValueSetPreExpansionStatusEnum.EXPANDED) {
|
||||
ourLog.warn("{} is present in terminology tables but not ready for persistence-backed invocation of operation $validation-code. Will perform in-memory code validation. Current status: {} | {}",
|
||||
getValueSetInfo(theValueSet), termValueSet.getExpansionStatus().name(), termValueSet.getExpansionStatus().getDescription());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected ValidateCodeResult validateCodeIsInPreExpandedValueSet(
|
||||
ValueSet theValueSet, String theSystem, String theCode, String theDisplay, Coding theCoding, CodeableConcept theCodeableConcept) {
|
||||
|
||||
ValidateUtil.isNotNullOrThrowUnprocessableEntity(theValueSet.hasId(), "ValueSet.id is required");
|
||||
|
||||
Long valueSetId = theValueSet.getIdElement().toUnqualifiedVersionless().getIdPartAsLong();
|
||||
Long valueSetResourcePid = getValueSetResourcePid(theValueSet.getIdElement());
|
||||
|
||||
List<TermValueSetConcept> concepts = new ArrayList<>();
|
||||
if (isNotBlank(theCode)) {
|
||||
if (isNotBlank(theSystem)) {
|
||||
concepts = myValueSetConceptDao.findOneByValueSetIdSystemAndCode(valueSetId, theSystem, theCode);
|
||||
concepts.addAll(findByValueSetResourcePidSystemAndCode(valueSetResourcePid, theSystem, theCode));
|
||||
} else {
|
||||
concepts = myValueSetConceptDao.findOneByValueSetIdAndCode(valueSetId, theCode);
|
||||
concepts.addAll(myValueSetConceptDao.findByValueSetResourcePidAndCode(valueSetResourcePid, theCode));
|
||||
}
|
||||
} else if (theCoding != null) {
|
||||
if (theCoding.hasSystem() && theCoding.hasCode()) {
|
||||
concepts = myValueSetConceptDao.findOneByValueSetIdSystemAndCode(valueSetId, theCoding.getSystem(), theCoding.getCode());
|
||||
concepts.addAll(findByValueSetResourcePidSystemAndCode(valueSetResourcePid, theCoding.getSystem(), theCoding.getCode()));
|
||||
}
|
||||
} else if (theCodeableConcept != null){
|
||||
for (Coding coding : theCodeableConcept.getCoding()) {
|
||||
if (coding.hasSystem() && coding.hasCode()) {
|
||||
concepts = myValueSetConceptDao.findOneByValueSetIdSystemAndCode(valueSetId, coding.getSystem(), coding.getCode());
|
||||
concepts.addAll(findByValueSetResourcePidSystemAndCode(valueSetResourcePid, coding.getSystem(), coding.getCode()));
|
||||
if (!concepts.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
|
@ -1002,6 +1018,15 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
|||
return null;
|
||||
}
|
||||
|
||||
private List<TermValueSetConcept> findByValueSetResourcePidSystemAndCode(Long theResourcePid, String theSystem, String theCode) {
|
||||
List<TermValueSetConcept> retVal = new ArrayList<>();
|
||||
Optional<TermValueSetConcept> optionalTermValueSetConcept = myValueSetConceptDao.findByValueSetResourcePidSystemAndCode(theResourcePid, theSystem, theCode);
|
||||
if (optionalTermValueSetConcept.isPresent()) {
|
||||
retVal.add(optionalTermValueSetConcept.get());
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private void fetchChildren(TermConcept theConcept, Set<TermConcept> theSetToPopulate) {
|
||||
for (TermConceptParentChildLink nextChildLink : theConcept.getChildren()) {
|
||||
TermConcept nextChild = nextChildLink.getChild();
|
||||
|
@ -1134,6 +1159,27 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
|||
|
||||
protected abstract CodeSystem getCodeSystemFromContext(String theSystem);
|
||||
|
||||
private Long getCodeSystemResourcePid(IIdType theIdType) {
|
||||
return getCodeSystemResourcePid(theIdType, null);
|
||||
}
|
||||
|
||||
private Long getCodeSystemResourcePid(IIdType theIdType, RequestDetails theRequestDetails) {
|
||||
return getResourcePid(myCodeSystemResourceDao, theIdType, theRequestDetails);
|
||||
}
|
||||
|
||||
private Long getValueSetResourcePid(IIdType theIdType) {
|
||||
return getValueSetResourcePid(theIdType, null);
|
||||
}
|
||||
|
||||
private Long getValueSetResourcePid(IIdType theIdType, RequestDetails theRequestDetails) {
|
||||
return getResourcePid(myValueSetResourceDao, theIdType, theRequestDetails);
|
||||
}
|
||||
|
||||
private Long getResourcePid(IFhirResourceDao<? extends IBaseResource> theResourceDao, IIdType theIdType, RequestDetails theRequestDetails) {
|
||||
ResourceTable resourceTable = (ResourceTable) theResourceDao.readEntity(theIdType, theRequestDetails);
|
||||
return resourceTable.getId();
|
||||
}
|
||||
|
||||
private void persistChildren(TermConcept theConcept, TermCodeSystemVersion theCodeSystem, IdentityHashMap<TermConcept, Object> theConceptsStack, int theTotalConcepts) {
|
||||
if (theConceptsStack.put(theConcept, PLACEHOLDER_OBJECT) != null) {
|
||||
return;
|
||||
|
@ -1467,6 +1513,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
|||
@PostConstruct
|
||||
public void start() {
|
||||
myCodeSystemResourceDao = myApplicationContext.getBean(IFhirResourceDaoCodeSystem.class);
|
||||
myValueSetResourceDao = myApplicationContext.getBean(IFhirResourceDaoValueSet.class);
|
||||
myTxTemplate = new TransactionTemplate(myTransactionManager);
|
||||
}
|
||||
|
||||
|
@ -1600,7 +1647,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
|||
if (theCodeSystem.getContent() == CodeSystem.CodeSystemContentMode.COMPLETE || theCodeSystem.getContent() == null || theCodeSystem.getContent() == CodeSystem.CodeSystemContentMode.NOTPRESENT) {
|
||||
ourLog.info("CodeSystem {} has a status of {}, going to store concepts in terminology tables", theResourceEntity.getIdDt().getValue(), theCodeSystem.getContentElement().getValueAsString());
|
||||
|
||||
Long codeSystemResourcePid = IDao.RESOURCE_PID.get(theCodeSystem);
|
||||
Long codeSystemResourcePid = getCodeSystemResourcePid(theCodeSystem.getIdElement());
|
||||
TermCodeSystemVersion persCs = myCodeSystemVersionDao.findCurrentVersionForCodeSystemResourcePid(codeSystemResourcePid);
|
||||
if (persCs != null) {
|
||||
ourLog.info("Code system version already exists in database");
|
||||
|
@ -1799,7 +1846,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
|||
|
||||
@Scheduled(fixedDelay = 600000) // 10 minutes.
|
||||
@Override
|
||||
public synchronized void preExpandValueSetToTerminologyTables() {
|
||||
public synchronized void preExpandDeferredValueSetsToTerminologyTables() {
|
||||
if (isNotSafeToPreExpandValueSets()) {
|
||||
ourLog.info("Skipping scheduled pre-expansion of ValueSets while deferred entities are being loaded.");
|
||||
return;
|
||||
|
|
|
@ -153,4 +153,9 @@ public class HapiTerminologySvcDstu2 extends BaseHapiTerminologySvcImpl {
|
|||
public ValidateCodeResult validateCodeIsInPreExpandedValueSet(IBaseResource theValueSet, String theSystem, String theCode, String theDisplay, IBaseDatatype theCoding, IBaseDatatype theCodeableConcept) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValueSetPreExpandedForCodeValidation(IBaseResource theValueSet) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
|||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.util.CoverageIgnore;
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
import ca.uhn.fhir.util.ValidateUtil;
|
||||
import org.hl7.fhir.convertors.VersionConvertor_30_40;
|
||||
import org.hl7.fhir.dstu3.hapi.ctx.IValidationSupport;
|
||||
import org.hl7.fhir.dstu3.model.*;
|
||||
|
@ -364,24 +365,33 @@ public class HapiTerminologySvcDstu3 extends BaseHapiTerminologySvcImpl implemen
|
|||
|
||||
@Override
|
||||
public ValidateCodeResult validateCodeIsInPreExpandedValueSet(IBaseResource theValueSet, String theSystem, String theCode, String theDisplay, IBaseDatatype theCoding, IBaseDatatype theCodeableConcept) {
|
||||
ValidateUtil.isNotNullOrThrowUnprocessableEntity(theValueSet, "ValueSet must not be null");
|
||||
ValueSet valueSet = (ValueSet) theValueSet;
|
||||
org.hl7.fhir.r4.model.ValueSet valueSetR4 = VersionConvertor_30_40.convertValueSet(valueSet);
|
||||
|
||||
Coding coding = (Coding) theCoding;
|
||||
org.hl7.fhir.r4.model.Coding codingR4 = null;
|
||||
if (coding != null) {
|
||||
codingR4 = new org.hl7.fhir.r4.model.Coding(coding.getSystem(), coding.getCode(), coding.getDisplay());
|
||||
}
|
||||
|
||||
CodeableConcept codeableConcept = (CodeableConcept) theCodeableConcept;
|
||||
|
||||
try {
|
||||
org.hl7.fhir.r4.model.ValueSet valueSetR4;
|
||||
valueSetR4 = VersionConvertor_30_40.convertValueSet(valueSet);
|
||||
|
||||
org.hl7.fhir.r4.model.Coding codingR4 = new org.hl7.fhir.r4.model.Coding(coding.getSystem(), coding.getCode(), coding.getDisplay());
|
||||
|
||||
org.hl7.fhir.r4.model.CodeableConcept codeableConceptR4 = new org.hl7.fhir.r4.model.CodeableConcept();
|
||||
org.hl7.fhir.r4.model.CodeableConcept codeableConceptR4 = null;
|
||||
if (codeableConcept != null) {
|
||||
codeableConceptR4 = new org.hl7.fhir.r4.model.CodeableConcept();
|
||||
for (Coding nestedCoding : codeableConcept.getCoding()) {
|
||||
codeableConceptR4.addCoding(new org.hl7.fhir.r4.model.Coding(nestedCoding.getSystem(), nestedCoding.getCode(), nestedCoding.getDisplay()));
|
||||
}
|
||||
|
||||
return super.validateCodeIsInPreExpandedValueSet(valueSetR4, theSystem, theCode, theDisplay, codingR4, codeableConceptR4);
|
||||
} catch (FHIRException e) {
|
||||
throw new InternalErrorException(e);
|
||||
}
|
||||
|
||||
return super.validateCodeIsInPreExpandedValueSet(valueSetR4, theSystem, theCode, theDisplay, codingR4, codeableConceptR4);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValueSetPreExpandedForCodeValidation(IBaseResource theValueSet) {
|
||||
ValidateUtil.isNotNullOrThrowUnprocessableEntity(theValueSet, "ValueSet must not be null");
|
||||
ValueSet valueSet = (ValueSet) theValueSet;
|
||||
org.hl7.fhir.r4.model.ValueSet valueSetR4 = VersionConvertor_30_40.convertValueSet(valueSet);
|
||||
return super.isValueSetPreExpandedForCodeValidation(valueSetR4);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -284,4 +284,10 @@ public class HapiTerminologySvcR4 extends BaseHapiTerminologySvcImpl implements
|
|||
CodeableConcept codeableConcept = (CodeableConcept) theCodeableConcept;
|
||||
return super.validateCodeIsInPreExpandedValueSet(valueSet, theSystem, theCode, theDisplay, coding, codeableConcept);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValueSetPreExpandedForCodeValidation(IBaseResource theValueSet) {
|
||||
ValueSet valueSet = (ValueSet) theValueSet;
|
||||
return super.isValueSetPreExpandedForCodeValidation(valueSet);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,11 +7,12 @@ import ca.uhn.fhir.jpa.entity.TermConcept;
|
|||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||
import ca.uhn.fhir.util.CoverageIgnore;
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
import ca.uhn.fhir.util.ValidateUtil;
|
||||
import org.hl7.fhir.instance.model.api.IBaseDatatype;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.r5.model.*;
|
||||
import org.hl7.fhir.r5.hapi.ctx.IValidationSupport;
|
||||
import org.hl7.fhir.r5.model.*;
|
||||
import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionComponent;
|
||||
import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent;
|
||||
import org.hl7.fhir.r5.terminologies.ValueSetExpander;
|
||||
|
@ -291,17 +292,33 @@ public class HapiTerminologySvcR5 extends BaseHapiTerminologySvcImpl implements
|
|||
|
||||
@Override
|
||||
public ValidateCodeResult validateCodeIsInPreExpandedValueSet(IBaseResource theValueSet, String theSystem, String theCode, String theDisplay, IBaseDatatype theCoding, IBaseDatatype theCodeableConcept) {
|
||||
org.hl7.fhir.r4.model.ValueSet valueSetR4 = org.hl7.fhir.convertors.conv40_50.ValueSet.convertValueSet((ValueSet) theValueSet);
|
||||
ValidateUtil.isNotNullOrThrowUnprocessableEntity(theValueSet, "ValueSet must not be null");
|
||||
ValueSet valueSet = (ValueSet) theValueSet;
|
||||
org.hl7.fhir.r4.model.ValueSet valueSetR4 = org.hl7.fhir.convertors.conv40_50.ValueSet.convertValueSet(valueSet);
|
||||
|
||||
Coding coding = (Coding) theCoding;
|
||||
org.hl7.fhir.r4.model.Coding codingR4 = new org.hl7.fhir.r4.model.Coding(coding.getSystem(), coding.getCode(), coding.getDisplay());
|
||||
org.hl7.fhir.r4.model.Coding codingR4 = null;
|
||||
if (coding != null) {
|
||||
codingR4 = new org.hl7.fhir.r4.model.Coding(coding.getSystem(), coding.getCode(), coding.getDisplay());
|
||||
}
|
||||
|
||||
CodeableConcept codeableConcept = (CodeableConcept) theCodeableConcept;
|
||||
org.hl7.fhir.r4.model.CodeableConcept codeableConceptR4 = new org.hl7.fhir.r4.model.CodeableConcept();
|
||||
for (Coding nestedCoding : codeableConcept.getCoding()) {
|
||||
codeableConceptR4.addCoding(new org.hl7.fhir.r4.model.Coding(nestedCoding.getSystem(), nestedCoding.getCode(), nestedCoding.getDisplay()));
|
||||
org.hl7.fhir.r4.model.CodeableConcept codeableConceptR4 = null;
|
||||
if (codeableConcept != null) {
|
||||
codeableConceptR4 = new org.hl7.fhir.r4.model.CodeableConcept();
|
||||
for (Coding nestedCoding : codeableConcept.getCoding()) {
|
||||
codeableConceptR4.addCoding(new org.hl7.fhir.r4.model.Coding(nestedCoding.getSystem(), nestedCoding.getCode(), nestedCoding.getDisplay()));
|
||||
}
|
||||
}
|
||||
|
||||
return super.validateCodeIsInPreExpandedValueSet(valueSetR4, theSystem, theCode, theDisplay, codingR4, codeableConceptR4);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValueSetPreExpandedForCodeValidation(IBaseResource theValueSet) {
|
||||
ValidateUtil.isNotNullOrThrowUnprocessableEntity(theValueSet, "ValueSet must not be null");
|
||||
ValueSet valueSet = (ValueSet) theValueSet;
|
||||
org.hl7.fhir.r4.model.ValueSet valueSetR4 = org.hl7.fhir.convertors.conv40_50.ValueSet.convertValueSet(valueSet);
|
||||
return super.isValueSetPreExpandedForCodeValidation(valueSetR4);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -111,10 +111,17 @@ public interface IHapiTerminologySvc {
|
|||
|
||||
AtomicInteger applyDeltaCodesystemsRemove(String theSystem, CodeSystem theDelta);
|
||||
|
||||
void preExpandValueSetToTerminologyTables();
|
||||
void preExpandDeferredValueSetsToTerminologyTables();
|
||||
|
||||
/**
|
||||
* Version independent
|
||||
*/
|
||||
ValidateCodeResult validateCodeIsInPreExpandedValueSet(IBaseResource theValueSet, String theSystem, String theCode, String theDisplay, IBaseDatatype theCoding, IBaseDatatype theCodeableConcept);
|
||||
|
||||
boolean isValueSetPreExpandedForCodeValidation(ValueSet theValueSet);
|
||||
|
||||
/**
|
||||
* Version independent
|
||||
*/
|
||||
boolean isValueSetPreExpandedForCodeValidation(IBaseResource theValueSet);
|
||||
}
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
package ca.uhn.fhir.jpa.dao.r4;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet.ValidateCodeResult;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.*;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -22,6 +20,10 @@ public class FhirResourceDaoR4ValueSetTest extends BaseJpaR4Test {
|
|||
|
||||
private IIdType myExtensionalVsId;
|
||||
|
||||
@After
|
||||
public void after() {
|
||||
myDaoConfig.setPreExpandValueSetsExperimental(new DaoConfig().isPreExpandValueSetsExperimental());
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
|
@ -124,6 +126,33 @@ public class FhirResourceDaoR4ValueSetTest extends BaseJpaR4Test {
|
|||
assertEquals("Systolic blood pressure at First encounter", result.getDisplay());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateCodeOperationByResourceIdAndCodeableConceptWithExistingValueSetAndPreExpansionEnabled() {
|
||||
myDaoConfig.setPreExpandValueSetsExperimental(true);
|
||||
|
||||
UriType valueSetIdentifier = null;
|
||||
IIdType id = myExtensionalVsId;
|
||||
CodeType code = null;
|
||||
UriType system = null;
|
||||
StringType display = null;
|
||||
Coding coding = null;
|
||||
CodeableConcept codeableConcept = new CodeableConcept();
|
||||
codeableConcept.addCoding().setSystem("http://acme.org").setCode("11378-7");
|
||||
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept, mySrd);
|
||||
assertTrue(result.isResult());
|
||||
assertEquals("Systolic blood pressure at First encounter", result.getDisplay());
|
||||
|
||||
myTermSvc.saveDeferred();
|
||||
result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept, mySrd);
|
||||
assertTrue(result.isResult());
|
||||
assertEquals("Systolic blood pressure at First encounter", result.getDisplay());
|
||||
|
||||
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
|
||||
result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept, mySrd);
|
||||
assertTrue(result.isResult());
|
||||
assertEquals("Systolic blood pressure at First encounter", result.getDisplay());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateCodeOperationByResourceIdAndCodeAndSystem() {
|
||||
UriType valueSetIdentifier = null;
|
||||
|
@ -138,6 +167,32 @@ public class FhirResourceDaoR4ValueSetTest extends BaseJpaR4Test {
|
|||
assertEquals("Systolic blood pressure at First encounter", result.getDisplay());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateCodeOperationByResourceIdAndCodeAndSystemWithExistingValueSetAndPreExpansionEnabled() {
|
||||
myDaoConfig.setPreExpandValueSetsExperimental(true);
|
||||
|
||||
UriType valueSetIdentifier = null;
|
||||
IIdType id = myExtensionalVsId;
|
||||
CodeType code = new CodeType("11378-7");
|
||||
UriType system = new UriType("http://acme.org");
|
||||
StringType display = null;
|
||||
Coding coding = null;
|
||||
CodeableConcept codeableConcept = null;
|
||||
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept, mySrd);
|
||||
assertTrue(result.isResult());
|
||||
assertEquals("Systolic blood pressure at First encounter", result.getDisplay());
|
||||
|
||||
myTermSvc.saveDeferred();
|
||||
result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept, mySrd);
|
||||
assertTrue(result.isResult());
|
||||
assertEquals("Systolic blood pressure at First encounter", result.getDisplay());
|
||||
|
||||
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
|
||||
result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept, mySrd);
|
||||
assertTrue(result.isResult());
|
||||
assertEquals("Systolic blood pressure at First encounter", result.getDisplay());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpandById() throws IOException {
|
||||
String resp;
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
package ca.uhn.fhir.jpa.entity;
|
||||
|
||||
import ca.uhn.fhir.i18n.HapiLocalizer;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
public class TermValueSetPreExpansionStatusEnumTest {
|
||||
@Test
|
||||
public void testHaveDescriptions() {
|
||||
HapiLocalizer localizer = new HapiLocalizer();
|
||||
|
||||
for (TermValueSetPreExpansionStatusEnum next : TermValueSetPreExpansionStatusEnum.values()) {
|
||||
String key = "ca.uhn.fhir.jpa.entity.TermValueSetPreExpansionStatusEnum." + next.getCode();
|
||||
String msg = localizer.getMessage(key);
|
||||
if (msg.equals(HapiLocalizer.UNKNOWN_I18N_KEY_MESSAGE)) {
|
||||
fail("No value for key: " + key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -600,7 +600,9 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
|
|||
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
|
||||
@Override
|
||||
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
|
||||
TermCodeSystem codeSystem = myTermCodeSystemDao.findByResourcePid(codeSystemId.getIdPartAsLong());
|
||||
ResourceTable resourceTable = (ResourceTable) myCodeSystemDao.readEntity(codeSystemResource.getIdElement(), null);
|
||||
Long codeSystemResourcePid = resourceTable.getId();
|
||||
TermCodeSystem codeSystem = myTermCodeSystemDao.findByResourcePid(codeSystemResourcePid);
|
||||
assertEquals(CS_URL, codeSystem.getCodeSystemUri());
|
||||
assertEquals("SYSTEM NAME", codeSystem.getName());
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -18,10 +18,7 @@ import org.hl7.fhir.instance.model.api.IIdType;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.messaging.MessageHandler;
|
||||
import org.springframework.messaging.MessagingException;
|
||||
import org.springframework.messaging.*;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Collection;
|
||||
|
@ -163,14 +160,7 @@ public class SubscriptionMatchingSubscriber implements MessageHandler {
|
|||
return;
|
||||
}
|
||||
|
||||
ResourceDeliveryJsonMessage wrappedMsg = new ResourceDeliveryJsonMessage(deliveryMsg);
|
||||
MessageChannel deliveryChannel = nextActiveSubscription.getSubscribableChannel();
|
||||
if (deliveryChannel != null) {
|
||||
resourceMatched = true;
|
||||
deliveryChannel.send(wrappedMsg);
|
||||
} else {
|
||||
ourLog.warn("Do not have delivery channel for subscription {}", nextActiveSubscription.getIdElement(myFhirContext));
|
||||
}
|
||||
resourceMatched |= sendToDeliveryChannel(nextActiveSubscription, deliveryMsg);
|
||||
}
|
||||
|
||||
if (!resourceMatched) {
|
||||
|
@ -181,6 +171,31 @@ public class SubscriptionMatchingSubscriber implements MessageHandler {
|
|||
}
|
||||
}
|
||||
|
||||
private boolean sendToDeliveryChannel(ActiveSubscription nextActiveSubscription, ResourceDeliveryMessage theDeliveryMsg) {
|
||||
boolean retval = false;
|
||||
ResourceDeliveryJsonMessage wrappedMsg = new ResourceDeliveryJsonMessage(theDeliveryMsg);
|
||||
MessageChannel deliveryChannel = nextActiveSubscription.getSubscribableChannel();
|
||||
if (deliveryChannel != null) {
|
||||
retval = true;
|
||||
trySendToDeliveryChannel(wrappedMsg, deliveryChannel);
|
||||
} else {
|
||||
ourLog.warn("Do not have delivery channel for subscription {}", nextActiveSubscription.getIdElement(myFhirContext));
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
private void trySendToDeliveryChannel(ResourceDeliveryJsonMessage theWrappedMsg, MessageChannel theDeliveryChannel) {
|
||||
try {
|
||||
boolean success = theDeliveryChannel.send(theWrappedMsg);
|
||||
if (!success) {
|
||||
ourLog.warn("Failed to send message to Delivery Channel.");
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
ourLog.error("Failed to send message to Delivery Channel", e);
|
||||
throw new RuntimeException("Failed to send message to Delivery Channel", e);
|
||||
}
|
||||
}
|
||||
|
||||
private String getId(ActiveSubscription theActiveSubscription) {
|
||||
return theActiveSubscription.getIdElement(myFhirContext).toUnqualifiedVersionless().getValue();
|
||||
}
|
||||
|
|
4
pom.xml
4
pom.xml
|
@ -547,6 +547,10 @@
|
|||
<id>nickrobison-usds</id>
|
||||
<name>Nick Robison</name>
|
||||
</developer>
|
||||
<developer>
|
||||
<id>fitzoh</id>
|
||||
<name>Andrew Fitzgerald</name>
|
||||
</developer>
|
||||
</developers>
|
||||
|
||||
<licenses>
|
||||
|
|
|
@ -102,6 +102,10 @@
|
|||
identifies the LOINC CodeSystem in <![CDATA[<code>ValueSet.compose.include.system</code>]]>. This ValueSet
|
||||
includes all LOINC codes.
|
||||
</action>
|
||||
<action type="add" issue="1461">
|
||||
A note has been added to the downloads page explaning the removal of the hapi-fhir-utilities
|
||||
module. Thanks to Andrew Fitzgerald for the PR!
|
||||
</action>
|
||||
</release>
|
||||
<release version="4.0.0" date="2019-08-14" description="Igloo">
|
||||
<action type="add">
|
||||
|
|
Loading…
Reference in New Issue