Merge remote-tracking branch 'origin/master' into 2849_add_new_mdm_param

This commit is contained in:
Nick Goupinets 2021-08-04 11:06:35 -04:00
commit 2bc024fef9
15 changed files with 418 additions and 200 deletions

View File

@ -0,0 +1,5 @@
---
type: add
issue: 2786
title: "Add 'loinc.codesystem.make.current' property to upload-terminology command to allow loading LOINC version
without becoming current."

View File

@ -27,14 +27,14 @@ import ca.uhn.fhir.context.support.ValidationSupportContext;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoCodeSystem; import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoCodeSystem;
import ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao; import ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao;
import ca.uhn.fhir.jpa.model.cross.IBasePersistedResource; import ca.uhn.fhir.jpa.model.cross.IBasePersistedResource;
import ca.uhn.fhir.jpa.term.api.ITermDeferredStorageSvc;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.rest.api.server.storage.TransactionDetails;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.jpa.term.api.ITermCodeSystemStorageSvc; import ca.uhn.fhir.jpa.term.api.ITermCodeSystemStorageSvc;
import ca.uhn.fhir.jpa.term.api.ITermDeferredStorageSvc;
import ca.uhn.fhir.jpa.util.LogicUtil; import ca.uhn.fhir.jpa.util.LogicUtil;
import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
import ca.uhn.fhir.rest.api.server.storage.TransactionDetails;
import ca.uhn.fhir.rest.param.TokenParam; import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
@ -52,7 +52,6 @@ import java.util.List;
import java.util.Set; import java.util.Set;
import static ca.uhn.fhir.jpa.dao.FhirResourceDaoValueSetDstu2.toStringOrNull; import static ca.uhn.fhir.jpa.dao.FhirResourceDaoValueSetDstu2.toStringOrNull;
import static ca.uhn.fhir.jpa.dao.dstu3.FhirResourceDaoValueSetDstu3.vsValidateCodeOptions;
import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank;
public class FhirResourceDaoCodeSystemR4 extends BaseHapiFhirResourceDao<CodeSystem> implements IFhirResourceDaoCodeSystem<CodeSystem, Coding, CodeableConcept> { public class FhirResourceDaoCodeSystemR4 extends BaseHapiFhirResourceDao<CodeSystem> implements IFhirResourceDaoCodeSystem<CodeSystem, Coding, CodeableConcept> {
@ -147,7 +146,7 @@ public class FhirResourceDaoCodeSystemR4 extends BaseHapiFhirResourceDao<CodeSys
CodeSystem cs = (CodeSystem) theResource; CodeSystem cs = (CodeSystem) theResource;
addPidToResource(theEntity, theResource); addPidToResource(theEntity, theResource);
myTerminologyCodeSystemStorageSvc.storeNewCodeSystemVersionIfNeeded(cs, (ResourceTable) theEntity); myTerminologyCodeSystemStorageSvc.storeNewCodeSystemVersionIfNeeded(cs, (ResourceTable) theEntity, theRequest);
} }
return retVal; return retVal;

View File

@ -86,9 +86,6 @@ import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.apache.commons.lang3.StringUtils.defaultIfBlank;
import static org.apache.commons.lang3.StringUtils.defaultString;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank;
public class TermCodeSystemStorageSvcImpl implements ITermCodeSystemStorageSvc { public class TermCodeSystemStorageSvcImpl implements ITermCodeSystemStorageSvc {
@ -342,7 +339,7 @@ public class TermCodeSystemStorageSvcImpl implements ITermCodeSystemStorageSvc {
@Override @Override
@Transactional(propagation = Propagation.MANDATORY) @Transactional(propagation = Propagation.MANDATORY)
public void storeNewCodeSystemVersionIfNeeded(CodeSystem theCodeSystem, ResourceTable theResourceEntity) { public void storeNewCodeSystemVersionIfNeeded(CodeSystem theCodeSystem, ResourceTable theResourceEntity, RequestDetails theRequestDetails) {
if (theCodeSystem != null && isNotBlank(theCodeSystem.getUrl())) { if (theCodeSystem != null && isNotBlank(theCodeSystem.getUrl())) {
String codeSystemUrl = theCodeSystem.getUrl(); String codeSystemUrl = theCodeSystem.getUrl();
if (theCodeSystem.getContent() == CodeSystem.CodeSystemContentMode.COMPLETE || theCodeSystem.getContent() == null || theCodeSystem.getContent() == CodeSystem.CodeSystemContentMode.NOTPRESENT) { if (theCodeSystem.getContent() == CodeSystem.CodeSystemContentMode.COMPLETE || theCodeSystem.getContent() == null || theCodeSystem.getContent() == CodeSystem.CodeSystemContentMode.NOTPRESENT) {
@ -373,7 +370,8 @@ public class TermCodeSystemStorageSvcImpl implements ITermCodeSystemStorageSvc {
persCs.getConcepts().addAll(BaseTermReadSvcImpl.toPersistedConcepts(theCodeSystem.getConcept(), persCs)); persCs.getConcepts().addAll(BaseTermReadSvcImpl.toPersistedConcepts(theCodeSystem.getConcept(), persCs));
ourLog.debug("Code system has {} concepts", persCs.getConcepts().size()); ourLog.debug("Code system has {} concepts", persCs.getConcepts().size());
storeNewCodeSystemVersion(codeSystemResourcePid, codeSystemUrl, theCodeSystem.getName(), theCodeSystem.getVersion(), persCs, theResourceEntity); storeNewCodeSystemVersion(codeSystemResourcePid, codeSystemUrl, theCodeSystem.getName(),
theCodeSystem.getVersion(), persCs, theResourceEntity, theRequestDetails);
} }
} }
@ -381,13 +379,14 @@ public class TermCodeSystemStorageSvcImpl implements ITermCodeSystemStorageSvc {
@Override @Override
@Transactional @Transactional
public IIdType storeNewCodeSystemVersion(CodeSystem theCodeSystemResource, TermCodeSystemVersion theCodeSystemVersion, RequestDetails theRequest, List<ValueSet> theValueSets, List<ConceptMap> theConceptMaps) { public IIdType storeNewCodeSystemVersion(CodeSystem theCodeSystemResource, TermCodeSystemVersion theCodeSystemVersion,
RequestDetails theRequest, List<ValueSet> theValueSets, List<ConceptMap> theConceptMaps) {
assert TransactionSynchronizationManager.isActualTransactionActive(); assert TransactionSynchronizationManager.isActualTransactionActive();
Validate.notBlank(theCodeSystemResource.getUrl(), "theCodeSystemResource must have a URL"); Validate.notBlank(theCodeSystemResource.getUrl(), "theCodeSystemResource must have a URL");
// Note that this creates the TermCodeSystem and TermCodeSystemVersion entities if needed // Note that this creates the TermCodeSystem and TermCodeSystemVersion entities if needed
IIdType csId = myTerminologyVersionAdapterSvc.createOrUpdateCodeSystem(theCodeSystemResource); IIdType csId = myTerminologyVersionAdapterSvc.createOrUpdateCodeSystem(theCodeSystemResource, theRequest);
ResourcePersistentId codeSystemResourcePid = myIdHelperService.resolveResourcePersistentIds(RequestPartitionId.allPartitions(), csId.getResourceType(), csId.getIdPart()); ResourcePersistentId codeSystemResourcePid = myIdHelperService.resolveResourcePersistentIds(RequestPartitionId.allPartitions(), csId.getResourceType(), csId.getIdPart());
ResourceTable resource = myResourceTableDao.getOne(codeSystemResourcePid.getIdAsLong()); ResourceTable resource = myResourceTableDao.getOne(codeSystemResourcePid.getIdAsLong());
@ -396,7 +395,8 @@ public class TermCodeSystemStorageSvcImpl implements ITermCodeSystemStorageSvc {
populateCodeSystemVersionProperties(theCodeSystemVersion, theCodeSystemResource, resource); populateCodeSystemVersionProperties(theCodeSystemVersion, theCodeSystemResource, resource);
storeNewCodeSystemVersion(codeSystemResourcePid, theCodeSystemResource.getUrl(), theCodeSystemResource.getName(), theCodeSystemResource.getVersion(), theCodeSystemVersion, resource); storeNewCodeSystemVersion(codeSystemResourcePid, theCodeSystemResource.getUrl(), theCodeSystemResource.getName(),
theCodeSystemResource.getVersion(), theCodeSystemVersion, resource, theRequest);
myDeferredStorageSvc.addConceptMapsToStorageQueue(theConceptMaps); myDeferredStorageSvc.addConceptMapsToStorageQueue(theConceptMaps);
myDeferredStorageSvc.addValueSetsToStorageQueue(theValueSets); myDeferredStorageSvc.addValueSetsToStorageQueue(theValueSets);
@ -406,7 +406,9 @@ public class TermCodeSystemStorageSvcImpl implements ITermCodeSystemStorageSvc {
@Override @Override
@Transactional @Transactional
public void storeNewCodeSystemVersion(ResourcePersistentId theCodeSystemResourcePid, String theSystemUri, String theSystemName, String theCodeSystemVersionId, TermCodeSystemVersion theCodeSystemVersion, ResourceTable theCodeSystemResourceTable) { public void storeNewCodeSystemVersion(ResourcePersistentId theCodeSystemResourcePid, String theSystemUri,
String theSystemName, String theCodeSystemVersionId, TermCodeSystemVersion theCodeSystemVersion,
ResourceTable theCodeSystemResourceTable, RequestDetails theRequestDetails) {
assert TransactionSynchronizationManager.isActualTransactionActive(); assert TransactionSynchronizationManager.isActualTransactionActive();
ourLog.debug("Storing code system"); ourLog.debug("Storing code system");
@ -468,34 +470,42 @@ public class TermCodeSystemStorageSvcImpl implements ITermCodeSystemStorageSvc {
codeSystemToStore = myCodeSystemVersionDao.saveAndFlush(codeSystemToStore); codeSystemToStore = myCodeSystemVersionDao.saveAndFlush(codeSystemToStore);
} }
ourLog.debug("Saving code system"); // defaults to true
boolean isMakeVersionCurrent = theRequestDetails == null ||
codeSystem.setCurrentVersion(codeSystemToStore); (boolean) theRequestDetails.getUserData().getOrDefault(MAKE_LOADING_VERSION_CURRENT, Boolean.TRUE);
if (codeSystem.getPid() == null) { if (isMakeVersionCurrent) {
codeSystem = myCodeSystemDao.saveAndFlush(codeSystem); makeCodeSystemCurrentVersion(codeSystem, codeSystemToStore, conceptsToSave, totalCodeCount);
} }
ourLog.debug("Setting CodeSystemVersion[{}] on {} concepts...", codeSystem.getPid(), totalCodeCount);
for (TermConcept next : conceptsToSave) {
populateVersion(next, codeSystemToStore);
} }
ourLog.debug("Saving {} concepts...", totalCodeCount);
private void makeCodeSystemCurrentVersion(TermCodeSystem theCodeSystem, TermCodeSystemVersion theCodeSystemToStore,
Collection<TermConcept> theConceptsToSave, int theTotalCodeCount) {
theCodeSystem.setCurrentVersion(theCodeSystemToStore);
if (theCodeSystem.getPid() == null) {
theCodeSystem = myCodeSystemDao.saveAndFlush(theCodeSystem);
}
ourLog.debug("Setting CodeSystemVersion[{}] on {} concepts...", theCodeSystem.getPid(), theTotalCodeCount);
for (TermConcept next : theConceptsToSave) {
populateVersion(next, theCodeSystemToStore);
}
ourLog.debug("Saving {} concepts...", theTotalCodeCount);
IdentityHashMap<TermConcept, Object> conceptsStack2 = new IdentityHashMap<>(); IdentityHashMap<TermConcept, Object> conceptsStack2 = new IdentityHashMap<>();
for (TermConcept next : conceptsToSave) { for (TermConcept next : theConceptsToSave) {
persistChildren(next, codeSystemToStore, conceptsStack2, totalCodeCount); persistChildren(next, theCodeSystemToStore, conceptsStack2, theTotalCodeCount);
} }
ourLog.debug("Done saving concepts, flushing to database"); ourLog.debug("Done saving concepts, flushing to database");
if (! myDeferredStorageSvc.isStorageQueueEmpty()) {
if (myDeferredStorageSvc.isStorageQueueEmpty() == false) {
ourLog.info("Note that some concept saving has been deferred"); ourLog.info("Note that some concept saving has been deferred");
} }
} }
private TermCodeSystemVersion getExistingTermCodeSystemVersion(Long theCodeSystemVersionPid, String theCodeSystemVersion) { private TermCodeSystemVersion getExistingTermCodeSystemVersion(Long theCodeSystemVersionPid, String theCodeSystemVersion) {
TermCodeSystemVersion existing; TermCodeSystemVersion existing;
if (theCodeSystemVersion == null) { if (theCodeSystemVersion == null) {

View File

@ -1,9 +1,95 @@
package ca.uhn.fhir.jpa.term; package ca.uhn.fhir.jpa.term;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
import ca.uhn.fhir.jpa.entity.TermConcept;
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink;
import ca.uhn.fhir.jpa.entity.TermConceptProperty;
import ca.uhn.fhir.jpa.term.api.ITermCodeSystemStorageSvc;
import ca.uhn.fhir.jpa.term.api.ITermDeferredStorageSvc;
import ca.uhn.fhir.jpa.term.api.ITermLoaderSvc;
import ca.uhn.fhir.jpa.term.custom.CustomTerminologySet;
import ca.uhn.fhir.jpa.term.icd10cm.Icd10CmLoader;
import ca.uhn.fhir.jpa.term.loinc.LoincAnswerListHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincAnswerListLinkHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincConsumerNameHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincDocumentOntologyHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincGroupFileHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincGroupTermsFileHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincHierarchyHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincIeeeMedicalDeviceCodeHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincImagingDocumentCodeHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincLinguisticVariantHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincLinguisticVariantsHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincParentGroupFileHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincPartHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincPartLinkHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincPartRelatedCodeMappingHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincRsnaPlaybookHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincTop2000LabResultsSiHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincTop2000LabResultsUsHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincUniversalOrderSetHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincXmlFileZipContentsHandler;
import ca.uhn.fhir.jpa.term.loinc.PartTypeAndPartName;
import ca.uhn.fhir.jpa.term.snomedct.SctHandlerConcept;
import ca.uhn.fhir.jpa.term.snomedct.SctHandlerDescription;
import ca.uhn.fhir.jpa.term.snomedct.SctHandlerRelationship;
import ca.uhn.fhir.jpa.util.Counter;
import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.util.ClasspathUtil;
import ca.uhn.fhir.util.ValidateUtil;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Charsets;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;
import org.apache.commons.csv.QuoteMode;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.CodeSystem;
import org.hl7.fhir.r4.model.ConceptMap;
import org.hl7.fhir.r4.model.Enumerations;
import org.hl7.fhir.r4.model.ValueSet;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.xml.sax.SAXException;
import javax.annotation.Nonnull;
import javax.validation.constraints.NotNull;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Properties;
import java.util.Set;
import java.util.stream.Collectors;
import static ca.uhn.fhir.jpa.term.api.ITermCodeSystemStorageSvc.MAKE_LOADING_VERSION_CURRENT;
import static ca.uhn.fhir.jpa.term.loinc.LoincUploadPropertiesEnum.LOINC_ANSWERLIST_FILE; import static ca.uhn.fhir.jpa.term.loinc.LoincUploadPropertiesEnum.LOINC_ANSWERLIST_FILE;
import static ca.uhn.fhir.jpa.term.loinc.LoincUploadPropertiesEnum.LOINC_ANSWERLIST_FILE_DEFAULT; import static ca.uhn.fhir.jpa.term.loinc.LoincUploadPropertiesEnum.LOINC_ANSWERLIST_FILE_DEFAULT;
import static ca.uhn.fhir.jpa.term.loinc.LoincUploadPropertiesEnum.LOINC_ANSWERLIST_LINK_FILE; import static ca.uhn.fhir.jpa.term.loinc.LoincUploadPropertiesEnum.LOINC_ANSWERLIST_LINK_FILE;
import static ca.uhn.fhir.jpa.term.loinc.LoincUploadPropertiesEnum.LOINC_ANSWERLIST_LINK_FILE_DEFAULT; import static ca.uhn.fhir.jpa.term.loinc.LoincUploadPropertiesEnum.LOINC_ANSWERLIST_LINK_FILE_DEFAULT;
import static ca.uhn.fhir.jpa.term.loinc.LoincUploadPropertiesEnum.LOINC_CODESYSTEM_MAKE_CURRENT;
import static ca.uhn.fhir.jpa.term.loinc.LoincUploadPropertiesEnum.LOINC_CODESYSTEM_VERSION; import static ca.uhn.fhir.jpa.term.loinc.LoincUploadPropertiesEnum.LOINC_CODESYSTEM_VERSION;
import static ca.uhn.fhir.jpa.term.loinc.LoincUploadPropertiesEnum.LOINC_CONSUMER_NAME_FILE; import static ca.uhn.fhir.jpa.term.loinc.LoincUploadPropertiesEnum.LOINC_CONSUMER_NAME_FILE;
import static ca.uhn.fhir.jpa.term.loinc.LoincUploadPropertiesEnum.LOINC_CONSUMER_NAME_FILE_DEFAULT; import static ca.uhn.fhir.jpa.term.loinc.LoincUploadPropertiesEnum.LOINC_CONSUMER_NAME_FILE_DEFAULT;
@ -49,93 +135,6 @@ import static ca.uhn.fhir.jpa.term.loinc.LoincUploadPropertiesEnum.LOINC_UPLOAD_
import static org.apache.commons.lang3.StringUtils.isBlank; import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Properties;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;
import javax.validation.constraints.NotNull;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;
import org.apache.commons.csv.QuoteMode;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.CodeSystem;
import org.hl7.fhir.r4.model.ConceptMap;
import org.hl7.fhir.r4.model.Enumerations;
import org.hl7.fhir.r4.model.ValueSet;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.xml.sax.SAXException;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Charsets;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
import ca.uhn.fhir.jpa.entity.TermConcept;
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink;
import ca.uhn.fhir.jpa.entity.TermConceptProperty;
import ca.uhn.fhir.jpa.term.api.ITermCodeSystemStorageSvc;
import ca.uhn.fhir.jpa.term.api.ITermDeferredStorageSvc;
import ca.uhn.fhir.jpa.term.api.ITermLoaderSvc;
import ca.uhn.fhir.jpa.term.custom.CustomTerminologySet;
import ca.uhn.fhir.jpa.term.icd10cm.Icd10CmLoader;
import ca.uhn.fhir.jpa.term.loinc.LoincAnswerListHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincAnswerListLinkHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincConsumerNameHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincDocumentOntologyHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincGroupFileHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincGroupTermsFileHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincHierarchyHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincIeeeMedicalDeviceCodeHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincImagingDocumentCodeHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincLinguisticVariantHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincLinguisticVariantsHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincParentGroupFileHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincPartHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincPartLinkHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincPartRelatedCodeMappingHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincRsnaPlaybookHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincTop2000LabResultsSiHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincTop2000LabResultsUsHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincUniversalOrderSetHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincXmlFileZipContentsHandler;
import ca.uhn.fhir.jpa.term.loinc.PartTypeAndPartName;
import ca.uhn.fhir.jpa.term.snomedct.SctHandlerConcept;
import ca.uhn.fhir.jpa.term.snomedct.SctHandlerDescription;
import ca.uhn.fhir.jpa.term.snomedct.SctHandlerRelationship;
import ca.uhn.fhir.jpa.util.Counter;
import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.util.ClasspathUtil;
import ca.uhn.fhir.util.ValidateUtil;
/* /*
* #%L * #%L
* HAPI FHIR JPA Server * HAPI FHIR JPA Server
@ -200,7 +199,7 @@ public class TermLoaderSvcImpl implements ITermLoaderSvc {
@Override @Override
public UploadStatistics loadImgthla(List<FileDescriptor> theFiles, RequestDetails theRequestDetails) { public UploadStatistics loadImgthla(List<FileDescriptor> theFiles, RequestDetails theRequestDetails) {
try (LoadedFileDescriptors descriptors = new LoadedFileDescriptors(theFiles)) { try (LoadedFileDescriptors descriptors = getLoadedFileDescriptors(theFiles)) {
List<String> mandatoryFilenameFragments = Arrays.asList( List<String> mandatoryFilenameFragments = Arrays.asList(
IMGTHLA_HLA_NOM_TXT, IMGTHLA_HLA_NOM_TXT,
IMGTHLA_HLA_XML IMGTHLA_HLA_XML
@ -213,11 +212,25 @@ public class TermLoaderSvcImpl implements ITermLoaderSvc {
} }
} }
@VisibleForTesting
LoadedFileDescriptors getLoadedFileDescriptors(List<FileDescriptor> theFiles) {
return new LoadedFileDescriptors(theFiles);
}
@Override @Override
public UploadStatistics loadLoinc(List<FileDescriptor> theFiles, RequestDetails theRequestDetails) { public UploadStatistics loadLoinc(List<FileDescriptor> theFiles, RequestDetails theRequestDetails) {
try (LoadedFileDescriptors descriptors = new LoadedFileDescriptors(theFiles)) { try (LoadedFileDescriptors descriptors = getLoadedFileDescriptors(theFiles)) {
Properties uploadProperties = getProperties(descriptors, LOINC_UPLOAD_PROPERTIES_FILE.getCode()); Properties uploadProperties = getProperties(descriptors, LOINC_UPLOAD_PROPERTIES_FILE.getCode());
String codeSystemVersionId = uploadProperties.getProperty(LOINC_CODESYSTEM_VERSION.getCode());
boolean isMakeCurrentVersion = Boolean.parseBoolean(
uploadProperties.getProperty(LOINC_CODESYSTEM_MAKE_CURRENT.getCode(), "true"));
if (StringUtils.isBlank(codeSystemVersionId) && ! isMakeCurrentVersion) {
throw new InvalidRequestException("'" + LOINC_CODESYSTEM_VERSION.getCode() +
"' property is required when '" + LOINC_CODESYSTEM_MAKE_CURRENT.getCode() + "' property is 'false'");
}
List<String> mandatoryFilenameFragments = Arrays.asList( List<String> mandatoryFilenameFragments = Arrays.asList(
uploadProperties.getProperty(LOINC_ANSWERLIST_FILE.getCode(), LOINC_ANSWERLIST_FILE_DEFAULT.getCode()), uploadProperties.getProperty(LOINC_ANSWERLIST_FILE.getCode(), LOINC_ANSWERLIST_FILE_DEFAULT.getCode()),
uploadProperties.getProperty(LOINC_ANSWERLIST_LINK_FILE.getCode(), LOINC_ANSWERLIST_LINK_FILE_DEFAULT.getCode()), uploadProperties.getProperty(LOINC_ANSWERLIST_LINK_FILE.getCode(), LOINC_ANSWERLIST_LINK_FILE_DEFAULT.getCode()),
@ -255,21 +268,25 @@ public class TermLoaderSvcImpl implements ITermLoaderSvc {
ourLog.info("Beginning LOINC processing"); ourLog.info("Beginning LOINC processing");
if (isMakeCurrentVersion) {
String codeSystemVersionId = uploadProperties.getProperty(LOINC_CODESYSTEM_VERSION.getCode());
if (codeSystemVersionId != null) { if (codeSystemVersionId != null) {
// Load the code system with version and then remove the version property.
processLoincFiles(descriptors, theRequestDetails, uploadProperties, false); processLoincFiles(descriptors, theRequestDetails, uploadProperties, false);
uploadProperties.remove(LOINC_CODESYSTEM_VERSION.getCode()); uploadProperties.remove(LOINC_CODESYSTEM_VERSION.getCode());
} }
// Load the same code system with null version. This will become the default version. ourLog.info("Uploading CodeSystem and making it current version");
} else {
ourLog.info("Uploading CodeSystem without updating current version");
}
theRequestDetails.getUserData().put(MAKE_LOADING_VERSION_CURRENT, isMakeCurrentVersion);
return processLoincFiles(descriptors, theRequestDetails, uploadProperties, true); return processLoincFiles(descriptors, theRequestDetails, uploadProperties, true);
} }
} }
@Override @Override
public UploadStatistics loadSnomedCt(List<FileDescriptor> theFiles, RequestDetails theRequestDetails) { public UploadStatistics loadSnomedCt(List<FileDescriptor> theFiles, RequestDetails theRequestDetails) {
try (LoadedFileDescriptors descriptors = new LoadedFileDescriptors(theFiles)) { try (LoadedFileDescriptors descriptors = getLoadedFileDescriptors(theFiles)) {
List<String> expectedFilenameFragments = Arrays.asList( List<String> expectedFilenameFragments = Arrays.asList(
SCT_FILE_DESCRIPTION, SCT_FILE_DESCRIPTION,
@ -296,7 +313,7 @@ public class TermLoaderSvcImpl implements ITermLoaderSvc {
TermCodeSystemVersion codeSystemVersion = new TermCodeSystemVersion(); TermCodeSystemVersion codeSystemVersion = new TermCodeSystemVersion();
int count = 0; int count = 0;
try (LoadedFileDescriptors compressedDescriptors = new LoadedFileDescriptors(theFiles)) { try (LoadedFileDescriptors compressedDescriptors = getLoadedFileDescriptors(theFiles)) {
for (FileDescriptor nextDescriptor : compressedDescriptors.getUncompressedFileDescriptors()) { for (FileDescriptor nextDescriptor : compressedDescriptors.getUncompressedFileDescriptors()) {
if (nextDescriptor.getFilename().toLowerCase(Locale.US).endsWith(".xml")) { if (nextDescriptor.getFilename().toLowerCase(Locale.US).endsWith(".xml")) {
try (InputStream inputStream = nextDescriptor.getInputStream(); try (InputStream inputStream = nextDescriptor.getInputStream();
@ -319,7 +336,7 @@ public class TermLoaderSvcImpl implements ITermLoaderSvc {
@Override @Override
public UploadStatistics loadCustom(String theSystem, List<FileDescriptor> theFiles, RequestDetails theRequestDetails) { public UploadStatistics loadCustom(String theSystem, List<FileDescriptor> theFiles, RequestDetails theRequestDetails) {
try (LoadedFileDescriptors descriptors = new LoadedFileDescriptors(theFiles)) { try (LoadedFileDescriptors descriptors = getLoadedFileDescriptors(theFiles)) {
Optional<String> codeSystemContent = loadFile(descriptors, CUSTOM_CODESYSTEM_JSON, CUSTOM_CODESYSTEM_XML); Optional<String> codeSystemContent = loadFile(descriptors, CUSTOM_CODESYSTEM_JSON, CUSTOM_CODESYSTEM_XML);
CodeSystem codeSystem; CodeSystem codeSystem;
if (codeSystemContent.isPresent()) { if (codeSystemContent.isPresent()) {
@ -347,7 +364,7 @@ public class TermLoaderSvcImpl implements ITermLoaderSvc {
@Override @Override
public UploadStatistics loadDeltaAdd(String theSystem, List<FileDescriptor> theFiles, RequestDetails theRequestDetails) { public UploadStatistics loadDeltaAdd(String theSystem, List<FileDescriptor> theFiles, RequestDetails theRequestDetails) {
ourLog.info("Processing terminology delta ADD for system[{}] with files: {}", theSystem, theFiles.stream().map(t -> t.getFilename()).collect(Collectors.toList())); ourLog.info("Processing terminology delta ADD for system[{}] with files: {}", theSystem, theFiles.stream().map(t -> t.getFilename()).collect(Collectors.toList()));
try (LoadedFileDescriptors descriptors = new LoadedFileDescriptors(theFiles)) { try (LoadedFileDescriptors descriptors = getLoadedFileDescriptors(theFiles)) {
CustomTerminologySet terminologySet = CustomTerminologySet.load(descriptors, false); CustomTerminologySet terminologySet = CustomTerminologySet.load(descriptors, false);
return myCodeSystemStorageSvc.applyDeltaCodeSystemsAdd(theSystem, terminologySet); return myCodeSystemStorageSvc.applyDeltaCodeSystemsAdd(theSystem, terminologySet);
} }
@ -356,7 +373,7 @@ public class TermLoaderSvcImpl implements ITermLoaderSvc {
@Override @Override
public UploadStatistics loadDeltaRemove(String theSystem, List<FileDescriptor> theFiles, RequestDetails theRequestDetails) { public UploadStatistics loadDeltaRemove(String theSystem, List<FileDescriptor> theFiles, RequestDetails theRequestDetails) {
ourLog.info("Processing terminology delta REMOVE for system[{}] with files: {}", theSystem, theFiles.stream().map(t -> t.getFilename()).collect(Collectors.toList())); ourLog.info("Processing terminology delta REMOVE for system[{}] with files: {}", theSystem, theFiles.stream().map(t -> t.getFilename()).collect(Collectors.toList()));
try (LoadedFileDescriptors descriptors = new LoadedFileDescriptors(theFiles)) { try (LoadedFileDescriptors descriptors = getLoadedFileDescriptors(theFiles)) {
CustomTerminologySet terminologySet = CustomTerminologySet.load(descriptors, true); CustomTerminologySet terminologySet = CustomTerminologySet.load(descriptors, true);
return myCodeSystemStorageSvc.applyDeltaCodeSystemsRemove(theSystem, terminologySet); return myCodeSystemStorageSvc.applyDeltaCodeSystemsRemove(theSystem, terminologySet);
} }
@ -395,8 +412,9 @@ public class TermLoaderSvcImpl implements ITermLoaderSvc {
} }
@VisibleForTesting
@NotNull @NotNull
private Properties getProperties(LoadedFileDescriptors theDescriptors, String thePropertiesFile) { Properties getProperties(LoadedFileDescriptors theDescriptors, String thePropertiesFile) {
Properties retVal = new Properties(); Properties retVal = new Properties();
try (InputStream propertyStream = TermLoaderSvcImpl.class.getResourceAsStream("/ca/uhn/fhir/jpa/term/loinc/loincupload.properties")) { try (InputStream propertyStream = TermLoaderSvcImpl.class.getResourceAsStream("/ca/uhn/fhir/jpa/term/loinc/loincupload.properties")) {

View File

@ -21,6 +21,7 @@ package ca.uhn.fhir.jpa.term;
*/ */
import ca.uhn.fhir.jpa.term.api.ITermVersionAdapterSvc; import ca.uhn.fhir.jpa.term.api.ITermVersionAdapterSvc;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.CodeSystem; import org.hl7.fhir.r4.model.CodeSystem;
import org.hl7.fhir.r4.model.ConceptMap; import org.hl7.fhir.r4.model.ConceptMap;
@ -29,7 +30,7 @@ import org.hl7.fhir.r4.model.ValueSet;
public class TermVersionAdapterSvcDstu2 implements ITermVersionAdapterSvc { public class TermVersionAdapterSvcDstu2 implements ITermVersionAdapterSvc {
@Override @Override
public IIdType createOrUpdateCodeSystem(CodeSystem theCodeSystemResource) { public IIdType createOrUpdateCodeSystem(CodeSystem theCodeSystemResource, RequestDetails theRequestDetails) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }

View File

@ -22,6 +22,7 @@ package ca.uhn.fhir.jpa.term;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao; import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.term.api.ITermVersionAdapterSvc; import ca.uhn.fhir.jpa.term.api.ITermVersionAdapterSvc;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.util.UrlUtil; import ca.uhn.fhir.util.UrlUtil;
import org.hl7.fhir.dstu3.model.CodeSystem; import org.hl7.fhir.dstu3.model.CodeSystem;
@ -70,7 +71,7 @@ public class TermVersionAdapterSvcDstu3 extends BaseTermVersionAdapterSvcImpl im
} }
@Override @Override
public IIdType createOrUpdateCodeSystem(org.hl7.fhir.r4.model.CodeSystem theCodeSystemResource) { public IIdType createOrUpdateCodeSystem(org.hl7.fhir.r4.model.CodeSystem theCodeSystemResource, RequestDetails theRequestDetails) {
CodeSystem resourceToStore; CodeSystem resourceToStore;
try { try {
resourceToStore = convertCodeSystem(theCodeSystemResource); resourceToStore = convertCodeSystem(theCodeSystemResource);
@ -80,9 +81,9 @@ public class TermVersionAdapterSvcDstu3 extends BaseTermVersionAdapterSvcImpl im
validateCodeSystemForStorage(theCodeSystemResource); validateCodeSystemForStorage(theCodeSystemResource);
if (isBlank(resourceToStore.getIdElement().getIdPart())) { if (isBlank(resourceToStore.getIdElement().getIdPart())) {
String matchUrl = "CodeSystem?url=" + UrlUtil.escapeUrlParam(theCodeSystemResource.getUrl()); String matchUrl = "CodeSystem?url=" + UrlUtil.escapeUrlParam(theCodeSystemResource.getUrl());
return myCodeSystemResourceDao.update(resourceToStore, matchUrl).getId(); return myCodeSystemResourceDao.update(resourceToStore, matchUrl, theRequestDetails).getId();
} else { } else {
return myCodeSystemResourceDao.update(resourceToStore).getId(); return myCodeSystemResourceDao.update(resourceToStore, theRequestDetails).getId();
} }
} }

View File

@ -22,6 +22,7 @@ package ca.uhn.fhir.jpa.term;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao; import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.term.api.ITermVersionAdapterSvc; import ca.uhn.fhir.jpa.term.api.ITermVersionAdapterSvc;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.util.UrlUtil; import ca.uhn.fhir.util.UrlUtil;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.CodeSystem; import org.hl7.fhir.r4.model.CodeSystem;
@ -59,13 +60,13 @@ public class TermVersionAdapterSvcR4 extends BaseTermVersionAdapterSvcImpl imple
} }
@Override @Override
public IIdType createOrUpdateCodeSystem(org.hl7.fhir.r4.model.CodeSystem theCodeSystemResource) { public IIdType createOrUpdateCodeSystem(org.hl7.fhir.r4.model.CodeSystem theCodeSystemResource, RequestDetails theRequestDetails) {
validateCodeSystemForStorage(theCodeSystemResource); validateCodeSystemForStorage(theCodeSystemResource);
if (isBlank(theCodeSystemResource.getIdElement().getIdPart())) { if (isBlank(theCodeSystemResource.getIdElement().getIdPart())) {
String matchUrl = "CodeSystem?url=" + UrlUtil.escapeUrlParam(theCodeSystemResource.getUrl()); String matchUrl = "CodeSystem?url=" + UrlUtil.escapeUrlParam(theCodeSystemResource.getUrl());
return myCodeSystemResourceDao.update(theCodeSystemResource, matchUrl).getId(); return myCodeSystemResourceDao.update(theCodeSystemResource, matchUrl, theRequestDetails).getId();
} else { } else {
return myCodeSystemResourceDao.update(theCodeSystemResource).getId(); return myCodeSystemResourceDao.update(theCodeSystemResource, theRequestDetails).getId();
} }
} }

View File

@ -22,6 +22,7 @@ package ca.uhn.fhir.jpa.term;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao; import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.term.api.ITermVersionAdapterSvc; import ca.uhn.fhir.jpa.term.api.ITermVersionAdapterSvc;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.util.UrlUtil; import ca.uhn.fhir.util.UrlUtil;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r5.model.CodeSystem; import org.hl7.fhir.r5.model.CodeSystem;
@ -59,15 +60,15 @@ public class TermVersionAdapterSvcR5 extends BaseTermVersionAdapterSvcImpl imple
} }
@Override @Override
public IIdType createOrUpdateCodeSystem(org.hl7.fhir.r4.model.CodeSystem theCodeSystemResource) { public IIdType createOrUpdateCodeSystem(org.hl7.fhir.r4.model.CodeSystem theCodeSystemResource, RequestDetails theRequestDetails) {
validateCodeSystemForStorage(theCodeSystemResource); validateCodeSystemForStorage(theCodeSystemResource);
CodeSystem codeSystemR4 = org.hl7.fhir.convertors.conv40_50.CodeSystem40_50.convertCodeSystem(theCodeSystemResource); CodeSystem codeSystemR4 = org.hl7.fhir.convertors.conv40_50.CodeSystem40_50.convertCodeSystem(theCodeSystemResource);
if (isBlank(theCodeSystemResource.getIdElement().getIdPart())) { if (isBlank(theCodeSystemResource.getIdElement().getIdPart())) {
String matchUrl = "CodeSystem?url=" + UrlUtil.escapeUrlParam(theCodeSystemResource.getUrl()); String matchUrl = "CodeSystem?url=" + UrlUtil.escapeUrlParam(theCodeSystemResource.getUrl());
return myCodeSystemResourceDao.update(codeSystemR4, matchUrl).getId(); return myCodeSystemResourceDao.update(codeSystemR4, matchUrl, theRequestDetails).getId();
} else { } else {
return myCodeSystemResourceDao.update(codeSystemR4).getId(); return myCodeSystemResourceDao.update(codeSystemR4, theRequestDetails).getId();
} }
} }

View File

@ -20,7 +20,6 @@ package ca.uhn.fhir.jpa.term.api;
* #L% * #L%
*/ */
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
import ca.uhn.fhir.jpa.entity.TermCodeSystem; import ca.uhn.fhir.jpa.entity.TermCodeSystem;
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion; import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
import ca.uhn.fhir.jpa.entity.TermConcept; import ca.uhn.fhir.jpa.entity.TermConcept;
@ -28,10 +27,12 @@ import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.term.UploadStatistics; import ca.uhn.fhir.jpa.term.UploadStatistics;
import ca.uhn.fhir.jpa.term.custom.CustomTerminologySet; import ca.uhn.fhir.jpa.term.custom.CustomTerminologySet;
import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.CodeSystem; import org.hl7.fhir.r4.model.CodeSystem;
import org.hl7.fhir.r4.model.ValueSet; import org.hl7.fhir.r4.model.ValueSet;
import javax.transaction.Transactional;
import java.util.List; import java.util.List;
/** /**
@ -39,18 +40,48 @@ import java.util.List;
*/ */
public interface ITermCodeSystemStorageSvc { public interface ITermCodeSystemStorageSvc {
static final String MAKE_LOADING_VERSION_CURRENT = "make.loading.version.current";
void deleteCodeSystem(TermCodeSystem theCodeSystem); void deleteCodeSystem(TermCodeSystem theCodeSystem);
void deleteCodeSystemVersion(TermCodeSystemVersion theCodeSystemVersion); void deleteCodeSystemVersion(TermCodeSystemVersion theCodeSystemVersion);
void storeNewCodeSystemVersion(ResourcePersistentId theCodeSystemResourcePid, String theSystemUri, String theSystemName, String theSystemVersionId, TermCodeSystemVersion theCodeSystemVersion, ResourceTable theCodeSystemResourceTable);
void storeNewCodeSystemVersion(ResourcePersistentId theCodeSystemResourcePid, String theSystemUri, String theSystemName,
String theSystemVersionId, TermCodeSystemVersion theCodeSystemVersion, ResourceTable theCodeSystemResourceTable,
RequestDetails theRequestDetails);
/**
* Default implementation supports previous signature of method which was added RequestDetails parameter
*/
@Transactional
default void storeNewCodeSystemVersion(ResourcePersistentId theCodeSystemResourcePid, String theSystemUri, String theSystemName,
String theSystemVersionId, TermCodeSystemVersion theCodeSystemVersion, ResourceTable theCodeSystemResourceTable) {
storeNewCodeSystemVersion(theCodeSystemResourcePid, theSystemUri, theSystemName, theSystemVersionId,
theCodeSystemVersion, theCodeSystemResourceTable, null);
}
/** /**
* @return Returns the ID of the created/updated code system * @return Returns the ID of the created/updated code system
*/ */
IIdType storeNewCodeSystemVersion(org.hl7.fhir.r4.model.CodeSystem theCodeSystemResource, TermCodeSystemVersion theCodeSystemVersion, RequestDetails theRequestDetails, List<ValueSet> theValueSets, List<org.hl7.fhir.r4.model.ConceptMap> theConceptMaps); IIdType storeNewCodeSystemVersion(org.hl7.fhir.r4.model.CodeSystem theCodeSystemResource,
TermCodeSystemVersion theCodeSystemVersion, RequestDetails theRequestDetails, List<ValueSet> theValueSets,
List<org.hl7.fhir.r4.model.ConceptMap> theConceptMaps);
void storeNewCodeSystemVersionIfNeeded(CodeSystem theCodeSystem, ResourceTable theResourceEntity, RequestDetails theRequestDetails);
/**
* Default implementation supports previous signature of method which was added RequestDetails parameter
*/
default void storeNewCodeSystemVersionIfNeeded(CodeSystem theCodeSystem, ResourceTable theResourceEntity) {
storeNewCodeSystemVersionIfNeeded(theCodeSystem, theResourceEntity, null);
}
void storeNewCodeSystemVersionIfNeeded(CodeSystem theCodeSystem, ResourceTable theResourceEntity);
UploadStatistics applyDeltaCodeSystemsAdd(String theSystem, CustomTerminologySet theAdditions); UploadStatistics applyDeltaCodeSystemsAdd(String theSystem, CustomTerminologySet theAdditions);

View File

@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.term.api;
* #L% * #L%
*/ */
import ca.uhn.fhir.rest.api.server.RequestDetails;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.CodeSystem; import org.hl7.fhir.r4.model.CodeSystem;
import org.hl7.fhir.r4.model.ConceptMap; import org.hl7.fhir.r4.model.ConceptMap;
@ -32,7 +33,11 @@ import org.hl7.fhir.r4.model.ValueSet;
*/ */
public interface ITermVersionAdapterSvc { public interface ITermVersionAdapterSvc {
IIdType createOrUpdateCodeSystem(CodeSystem theCodeSystemResource); default IIdType createOrUpdateCodeSystem(CodeSystem theCodeSystemResource) {
return createOrUpdateCodeSystem(theCodeSystemResource, null);
}
IIdType createOrUpdateCodeSystem(CodeSystem theCodeSystemResource, RequestDetails theRequestDetails);
void createOrUpdateConceptMap(ConceptMap theNextConceptMap); void createOrUpdateConceptMap(ConceptMap theNextConceptMap);

View File

@ -101,6 +101,9 @@ public enum LoincUploadPropertiesEnum {
// This is the version identifier for the LOINC code system // This is the version identifier for the LOINC code system
LOINC_CODESYSTEM_VERSION("loinc.codesystem.version"), LOINC_CODESYSTEM_VERSION("loinc.codesystem.version"),
// Indicates if loading version has to become current
LOINC_CODESYSTEM_MAKE_CURRENT("loinc.codesystem.make.current"),
// This is the version identifier for the answer list file // This is the version identifier for the answer list file
LOINC_ANSWERLIST_VERSION("loinc.answerlist.version"), LOINC_ANSWERLIST_VERSION("loinc.answerlist.version"),

View File

@ -65,6 +65,10 @@ loinc.universal.lab.order.valueset.file=AccessoryFiles/LoincUniversalLabOrdersVa
## Key may be omitted if only a single version of LOINC is being kept. ## Key may be omitted if only a single version of LOINC is being kept.
#loinc.codesystem.version=2.68 #loinc.codesystem.version=2.68
# Indicates if version being loaded has to become current
## Default is true
loinc.codesystem.make.current=true
# This is the version identifier for the answer list file # This is the version identifier for the answer list file
## Key may be omitted ## Key may be omitted
loinc.answerlist.version=Beta.1 loinc.answerlist.version=Beta.1

View File

@ -29,6 +29,7 @@ import org.hl7.fhir.r4.model.ValueSet;
import org.hl7.fhir.r4.model.ValueSet.ConceptReferenceComponent; import org.hl7.fhir.r4.model.ValueSet.ConceptReferenceComponent;
import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Answers; import org.mockito.Answers;
@ -42,8 +43,10 @@ import org.springframework.transaction.PlatformTransactionManager;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static ca.uhn.fhir.jpa.term.api.ITermCodeSystemStorageSvc.MAKE_LOADING_VERSION_CURRENT;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.mockito.Mockito.when;
@ExtendWith(SpringExtension.class) @ExtendWith(SpringExtension.class)
@RequiresDocker @RequiresDocker
@ -83,6 +86,13 @@ public class FhirResourceDaoR4TerminologyElasticsearchIT extends BaseJpaTest {
@Autowired @Autowired
private IBulkDataExportSvc myBulkDataExportSvc; private IBulkDataExportSvc myBulkDataExportSvc;
@BeforeEach
public void beforeEach() {
when(mySrd.getUserData().getOrDefault(MAKE_LOADING_VERSION_CURRENT, Boolean.TRUE)).thenReturn(Boolean.TRUE);
}
@Test @Test
public void testExpandWithIncludeContainingDashesInInclude() { public void testExpandWithIncludeContainingDashesInInclude() {
CodeSystem codeSystem = new CodeSystem(); CodeSystem codeSystem = new CodeSystem();

View File

@ -1,9 +1,53 @@
package ca.uhn.fhir.jpa.term; package ca.uhn.fhir.jpa.term;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
import ca.uhn.fhir.jpa.entity.TermConcept;
import ca.uhn.fhir.jpa.entity.TermConceptDesignation;
import ca.uhn.fhir.jpa.entity.TermConceptProperty;
import ca.uhn.fhir.jpa.model.util.JpaConstants;
import ca.uhn.fhir.jpa.term.api.ITermCodeSystemStorageSvc;
import ca.uhn.fhir.jpa.term.api.ITermDeferredStorageSvc;
import ca.uhn.fhir.jpa.term.api.ITermLoaderSvc;
import ca.uhn.fhir.jpa.term.loinc.LoincDocumentOntologyHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincIeeeMedicalDeviceCodeHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincImagingDocumentCodeHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincPartRelatedCodeMappingHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincRsnaPlaybookHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincTop2000LabResultsSiHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincTop2000LabResultsUsHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincUniversalOrderSetHandler;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import org.hl7.fhir.r4.model.CodeSystem;
import org.hl7.fhir.r4.model.ConceptMap;
import org.hl7.fhir.r4.model.Enumerations;
import org.hl7.fhir.r4.model.ValueSet;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import static ca.uhn.fhir.jpa.term.api.ITermCodeSystemStorageSvc.MAKE_LOADING_VERSION_CURRENT;
import static ca.uhn.fhir.jpa.term.loinc.LoincUploadPropertiesEnum.LOINC_ANSWERLIST_DUPLICATE_FILE_DEFAULT; import static ca.uhn.fhir.jpa.term.loinc.LoincUploadPropertiesEnum.LOINC_ANSWERLIST_DUPLICATE_FILE_DEFAULT;
import static ca.uhn.fhir.jpa.term.loinc.LoincUploadPropertiesEnum.LOINC_ANSWERLIST_FILE_DEFAULT; import static ca.uhn.fhir.jpa.term.loinc.LoincUploadPropertiesEnum.LOINC_ANSWERLIST_FILE_DEFAULT;
import static ca.uhn.fhir.jpa.term.loinc.LoincUploadPropertiesEnum.LOINC_ANSWERLIST_LINK_DUPLICATE_FILE_DEFAULT; import static ca.uhn.fhir.jpa.term.loinc.LoincUploadPropertiesEnum.LOINC_ANSWERLIST_LINK_DUPLICATE_FILE_DEFAULT;
import static ca.uhn.fhir.jpa.term.loinc.LoincUploadPropertiesEnum.LOINC_ANSWERLIST_LINK_FILE_DEFAULT; import static ca.uhn.fhir.jpa.term.loinc.LoincUploadPropertiesEnum.LOINC_ANSWERLIST_LINK_FILE_DEFAULT;
import static ca.uhn.fhir.jpa.term.loinc.LoincUploadPropertiesEnum.LOINC_CODESYSTEM_MAKE_CURRENT;
import static ca.uhn.fhir.jpa.term.loinc.LoincUploadPropertiesEnum.LOINC_CODESYSTEM_VERSION;
import static ca.uhn.fhir.jpa.term.loinc.LoincUploadPropertiesEnum.LOINC_CONSUMER_NAME_FILE_DEFAULT; import static ca.uhn.fhir.jpa.term.loinc.LoincUploadPropertiesEnum.LOINC_CONSUMER_NAME_FILE_DEFAULT;
import static ca.uhn.fhir.jpa.term.loinc.LoincUploadPropertiesEnum.LOINC_DOCUMENT_ONTOLOGY_FILE_DEFAULT; import static ca.uhn.fhir.jpa.term.loinc.LoincUploadPropertiesEnum.LOINC_DOCUMENT_ONTOLOGY_FILE_DEFAULT;
import static ca.uhn.fhir.jpa.term.loinc.LoincUploadPropertiesEnum.LOINC_DUPLICATE_FILE_DEFAULT; import static ca.uhn.fhir.jpa.term.loinc.LoincUploadPropertiesEnum.LOINC_DUPLICATE_FILE_DEFAULT;
@ -30,49 +74,19 @@ import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail; import static org.junit.jupiter.api.Assertions.fail;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset; import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.hl7.fhir.r4.model.CodeSystem;
import org.hl7.fhir.r4.model.ConceptMap;
import org.hl7.fhir.r4.model.Enumerations;
import org.hl7.fhir.r4.model.ValueSet;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.jpa.entity.TermConcept;
import ca.uhn.fhir.jpa.entity.TermConceptDesignation;
import ca.uhn.fhir.jpa.entity.TermConceptProperty;
import ca.uhn.fhir.jpa.term.api.ITermCodeSystemStorageSvc;
import ca.uhn.fhir.jpa.term.api.ITermDeferredStorageSvc;
import ca.uhn.fhir.jpa.term.api.ITermLoaderSvc;
import ca.uhn.fhir.jpa.term.loinc.LoincDocumentOntologyHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincIeeeMedicalDeviceCodeHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincImagingDocumentCodeHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincPartRelatedCodeMappingHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincRsnaPlaybookHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincTop2000LabResultsSiHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincTop2000LabResultsUsHandler;
import ca.uhn.fhir.jpa.term.loinc.LoincUniversalOrderSetHandler;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
public class TerminologyLoaderSvcLoincTest extends BaseLoaderTest { public class TerminologyLoaderSvcLoincTest extends BaseLoaderTest {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TerminologyLoaderSvcLoincTest.class); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TerminologyLoaderSvcLoincTest.class);
private TermLoaderSvcImpl mySvc; private TermLoaderSvcImpl mySvc;
@ -99,6 +113,8 @@ public class TerminologyLoaderSvcLoincTest extends BaseLoaderTest {
private ArgumentCaptor<List<ConceptMap>> myConceptMapCaptor_267_second; private ArgumentCaptor<List<ConceptMap>> myConceptMapCaptor_267_second;
@Captor @Captor
private ArgumentCaptor<List<ConceptMap>> myConceptMapCaptor_268; private ArgumentCaptor<List<ConceptMap>> myConceptMapCaptor_268;
@Captor
private ArgumentCaptor<RequestDetails> myRequestDetailsCaptor;
private ZipCollectionBuilder myFiles; private ZipCollectionBuilder myFiles;
@Mock @Mock
private ITermDeferredStorageSvc myTermDeferredStorageSvc; private ITermDeferredStorageSvc myTermDeferredStorageSvc;
@ -822,6 +838,110 @@ public class TerminologyLoaderSvcLoincTest extends BaseLoaderTest {
assertEquals("LP52960-9", doublyNestedChildCode.getChildren().get(2).getChild().getCode()); assertEquals("LP52960-9", doublyNestedChildCode.getChildren().get(2).getChild().getCode());
} }
@Nested
public class LoadLoincCurrentVersion {
private TermLoaderSvcImpl testedSvc;
private final Properties testProps = new Properties();
@Mock private final LoadedFileDescriptors mockFileDescriptors = mock(LoadedFileDescriptors.class);
@SuppressWarnings("unchecked")
@Mock private final List<ITermLoaderSvc.FileDescriptor> mockFileDescriptorList = mock(List.class);
@Mock private final ITermCodeSystemStorageSvc mockCodeSystemStorageSvc = mock(ITermCodeSystemStorageSvc.class);
private final RequestDetails requestDetails = new ServletRequestDetails();
@BeforeEach
void beforeEach() {
testedSvc = spy(mySvc);
doReturn(testProps).when(testedSvc).getProperties(any(), eq(LOINC_UPLOAD_PROPERTIES_FILE.getCode()));
requestDetails.setOperation(JpaConstants.OPERATION_UPLOAD_EXTERNAL_CODE_SYSTEM);
}
@Test
public void testDontMakeCurrentVersion() throws IOException {
addLoincMandatoryFilesToZip(myFiles);
testProps.put(LOINC_CODESYSTEM_MAKE_CURRENT.getCode(), "false");
testProps.put(LOINC_CODESYSTEM_VERSION.getCode(), "27.0");
testedSvc.loadLoinc(myFiles.getFiles(), requestDetails);
verify(myTermCodeSystemStorageSvc, times(1)).storeNewCodeSystemVersion(
any(CodeSystem.class), any(TermCodeSystemVersion.class), myRequestDetailsCaptor.capture(), any(), any());
myRequestDetailsCaptor.getAllValues().forEach( rd ->
assertFalse(rd.getUserData() == null ||
(boolean) requestDetails.getUserData().getOrDefault(MAKE_LOADING_VERSION_CURRENT, Boolean.TRUE))
);
}
@Test
public void testMakeCurrentVersionPropertySet() {
testProps.put(LOINC_CODESYSTEM_MAKE_CURRENT.getCode(), "true");
testProps.put(LOINC_CODESYSTEM_VERSION.getCode(), "27.0");
doReturn(mockFileDescriptors).when(testedSvc).getLoadedFileDescriptors(mockFileDescriptorList);
doReturn(mock(UploadStatistics.class)).when(testedSvc).processLoincFiles(
eq(mockFileDescriptors), eq(requestDetails), eq(testProps), any());
testedSvc.loadLoinc(mockFileDescriptorList, requestDetails);
boolean isMakeCurrent = requestDetails.getUserData() == null ||
(boolean) requestDetails.getUserData().getOrDefault(MAKE_LOADING_VERSION_CURRENT, Boolean.TRUE);
assertTrue(isMakeCurrent);
}
@Test
public void testMakeCurrentVersionByDefaultPropertySet() {
testProps.put(LOINC_CODESYSTEM_VERSION.getCode(), "27.0");
doReturn(mockFileDescriptors).when(testedSvc).getLoadedFileDescriptors(mockFileDescriptorList);
doReturn(mock(UploadStatistics.class)).when(testedSvc).processLoincFiles(
eq(mockFileDescriptors), eq(requestDetails), eq(testProps), any());
testedSvc.loadLoinc(mockFileDescriptorList, requestDetails);
boolean isMakeCurrent = requestDetails.getUserData() == null ||
(boolean) requestDetails.getUserData().getOrDefault(MAKE_LOADING_VERSION_CURRENT, Boolean.TRUE);
assertTrue(isMakeCurrent);
}
@Test
public void testDontMakeCurrentVersionPropertySet() {
testProps.put(LOINC_CODESYSTEM_MAKE_CURRENT.getCode(), "false");
testProps.put(LOINC_CODESYSTEM_VERSION.getCode(), "27.0");
doReturn(mockFileDescriptors).when(testedSvc).getLoadedFileDescriptors(mockFileDescriptorList);
doReturn(mock(UploadStatistics.class)).when(testedSvc).processLoincFiles(
eq(mockFileDescriptors), eq(requestDetails), eq(testProps), any());
testedSvc.loadLoinc(mockFileDescriptorList, requestDetails);
boolean isMakeCurrent = requestDetails.getUserData() == null ||
(boolean) requestDetails.getUserData().getOrDefault(MAKE_LOADING_VERSION_CURRENT, Boolean.TRUE);
assertFalse(isMakeCurrent);
}
@Test
public void testNoVersionAndNoMakeCurrentThrows() {
testProps.put(LOINC_CODESYSTEM_MAKE_CURRENT.getCode(), "false");
doReturn(mockFileDescriptors).when(testedSvc).getLoadedFileDescriptors(mockFileDescriptorList);
InvalidRequestException thrown = Assertions.assertThrows(InvalidRequestException.class,
() -> testedSvc.loadLoinc(mockFileDescriptorList, mySrd) );
assertEquals("'" + LOINC_CODESYSTEM_VERSION.getCode() + "' property is required when '" +
LOINC_CODESYSTEM_MAKE_CURRENT.getCode() + "' property is 'false'", thrown.getMessage());
}
}
private static void verifyConsumerName(Collection<TermConceptDesignation> designationList, String theConsumerName) { private static void verifyConsumerName(Collection<TermConceptDesignation> designationList, String theConsumerName) {
TermConceptDesignation consumerNameDesignation = null; TermConceptDesignation consumerNameDesignation = null;

View File

@ -30,6 +30,7 @@ import org.hl7.fhir.r4.model.CodeableConcept;
import org.hl7.fhir.r4.model.Coding; import org.hl7.fhir.r4.model.Coding;
import org.hl7.fhir.r4.model.ValueSet; import org.hl7.fhir.r4.model.ValueSet;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Answers; import org.mockito.Answers;
@ -40,6 +41,7 @@ import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.PlatformTransactionManager;
import static ca.uhn.fhir.jpa.term.api.ITermCodeSystemStorageSvc.MAKE_LOADING_VERSION_CURRENT;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail; import static org.junit.jupiter.api.Assertions.fail;
import static org.mockito.ArgumentMatchers.anyCollection; import static org.mockito.ArgumentMatchers.anyCollection;
@ -90,6 +92,13 @@ public class ValueSetExpansionR4ElasticsearchIT extends BaseJpaTest {
@Mock @Mock
private IValueSetConceptAccumulator myValueSetCodeAccumulator; private IValueSetConceptAccumulator myValueSetCodeAccumulator;
@BeforeEach
public void beforeEach() {
when(mySrd.getUserData().getOrDefault(MAKE_LOADING_VERSION_CURRENT, Boolean.TRUE)).thenReturn(Boolean.TRUE);
}
@AfterEach @AfterEach
public void after() { public void after() {
myDaoConfig.setMaximumExpansionSize(DaoConfig.DEFAULT_MAX_EXPANSION_SIZE); myDaoConfig.setMaximumExpansionSize(DaoConfig.DEFAULT_MAX_EXPANSION_SIZE);