More work on loinc

This commit is contained in:
James Agnew 2018-03-19 08:51:02 -04:00
parent 30cd63b929
commit 6359f7f8a1
54 changed files with 1269 additions and 664 deletions

View File

@ -59,3 +59,6 @@ Top 2000
- Need to define a URI for both ValueSets. Currently I am using
"http://loinc.org/top-2000-lab-results-us" and
"http://loinc.org/top-2000-lab-results-si"
Universal Order Set
- Need to define a URI for this ValueSet - Currenty using "http://loinc.org/fhir/loinc-universal-order-set"

View File

@ -102,40 +102,130 @@ public interface IContextValidationSupport<EVS_IN, EVS_OUT, SDT, CST, CDCT, IST>
*/
CodeValidationResult<CDCT, IST> validateCode(FhirContext theContext, String theCodeSystem, String theCode, String theDisplay);
abstract class BaseConceptProperty {
private final String myPropertyName;
/**
* Constructor
*/
protected BaseConceptProperty(String thePropertyName) {
myPropertyName = thePropertyName;
}
public String getPropertyName() {
return myPropertyName;
}
}
class StringConceptProperty extends BaseConceptProperty {
private final String myValue;
/**
* Constructor
*
* @param theName The name
*/
public StringConceptProperty(String theName, String theValue) {
super(theName);
myValue = theValue;
}
public String getValue() {
return myValue;
}
}
class CodingConceptProperty extends BaseConceptProperty {
private final String myCode;
private final String myCodeSystem;
private final String myDisplay;
/**
* Constructor
*
* @param theName The name
*/
public CodingConceptProperty(String theName, String theCodeSystem, String theCode, String theDisplay) {
super(theName);
myCodeSystem = theCodeSystem;
myCode = theCode;
myDisplay = theDisplay;
}
public String getCode() {
return myCode;
}
public String getCodeSystem() {
return myCodeSystem;
}
public String getDisplay() {
return myDisplay;
}
}
class CodeValidationResult<CDCT, IST> {
private CDCT definition;
private String message;
private IST severity;
private CDCT myDefinition;
private String myMessage;
private IST mySeverity;
private String myCodeSystemName;
private String myCodeSystemVersion;
private List<BaseConceptProperty> myProperties;
public CodeValidationResult(CDCT theNext) {
this.definition = theNext;
this.myDefinition = theNext;
}
public CodeValidationResult(IST severity, String message) {
this.severity = severity;
this.message = message;
this.mySeverity = severity;
this.myMessage = message;
}
public CodeValidationResult(IST severity, String message, CDCT definition) {
this.severity = severity;
this.message = message;
this.definition = definition;
this.mySeverity = severity;
this.myMessage = message;
this.myDefinition = definition;
}
public CDCT asConceptDefinition() {
return definition;
return myDefinition;
}
public String getCodeSystemName() {
return myCodeSystemName;
}
public void setCodeSystemName(String theCodeSystemName) {
myCodeSystemName = theCodeSystemName;
}
public String getCodeSystemVersion() {
return myCodeSystemVersion;
}
public void setCodeSystemVersion(String theCodeSystemVersion) {
myCodeSystemVersion = theCodeSystemVersion;
}
public String getMessage() {
return message;
return myMessage;
}
public List<BaseConceptProperty> getProperties() {
return myProperties;
}
public void setProperties(List<BaseConceptProperty> theProperties) {
myProperties = theProperties;
}
public IST getSeverity() {
return severity;
return mySeverity;
}
public boolean isOk() {
return definition != null;
return myDefinition != null;
}
}

View File

@ -41,7 +41,7 @@ public class UploadTerminologyCommand extends BaseCommand {
opt.setRequired(true);
options.addOption(opt);
opt = new Option("u", "url", true, "The code system URL associated with this upload (e.g. " + IHapiTerminologyLoaderSvc.SCT_URL + ")");
opt = new Option("u", "url", true, "The code system URL associated with this upload (e.g. " + IHapiTerminologyLoaderSvc.SCT_URI + ")");
opt.setRequired(false);
options.addOption(opt);

View File

@ -11,7 +11,7 @@ import ca.uhn.fhir.jpa.provider.dstu3.JpaSystemProviderDstu3;
import ca.uhn.fhir.jpa.provider.dstu3.TerminologyUploaderProviderDstu3;
import ca.uhn.fhir.jpa.provider.r4.JpaConformanceProviderR4;
import ca.uhn.fhir.jpa.provider.r4.JpaSystemProviderR4;
import ca.uhn.fhir.jpa.provider.r4.TerminologyUploaderProviderR4;
import ca.uhn.fhir.jpa.provider.TerminologyUploaderProvider;
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
import ca.uhn.fhir.model.dstu2.resource.Bundle;
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
@ -24,11 +24,9 @@ import ca.uhn.fhir.rest.server.interceptor.CorsInterceptor;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.cors.CorsConfiguration;
import javax.servlet.ServletException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
@ -84,7 +82,7 @@ public class JpaServerDemo extends RestfulServer {
systemProvider.add(myAppCtx.getBean(TerminologyUploaderProviderDstu3.class));
} else if (fhirVersion == FhirVersionEnum.R4) {
systemProvider.add(myAppCtx.getBean("mySystemProviderR4", JpaSystemProviderR4.class));
systemProvider.add(myAppCtx.getBean(TerminologyUploaderProviderR4.class));
systemProvider.add(myAppCtx.getBean(TerminologyUploaderProvider.class));
} else {
throw new IllegalStateException();
}

View File

@ -9,7 +9,7 @@ import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc;
import ca.uhn.fhir.jpa.dao.ISearchParamRegistry;
import ca.uhn.fhir.jpa.dao.dstu3.SearchParamExtractorDstu3;
import ca.uhn.fhir.jpa.dao.dstu3.SearchParamRegistryDstu3;
import ca.uhn.fhir.jpa.provider.dstu3.TerminologyUploaderProviderDstu3;
import ca.uhn.fhir.jpa.provider.TerminologyUploaderProvider;
import ca.uhn.fhir.jpa.term.*;
import ca.uhn.fhir.jpa.validation.JpaValidationSupportChainDstu3;
import ca.uhn.fhir.validation.IValidatorModule;
@ -115,8 +115,8 @@ public class BaseDstu3Config extends BaseConfig {
}
@Bean(autowire = Autowire.BY_TYPE)
public TerminologyUploaderProviderDstu3 terminologyUploaderProvider() {
TerminologyUploaderProviderDstu3 retVal = new TerminologyUploaderProviderDstu3();
public TerminologyUploaderProvider terminologyUploaderProvider() {
TerminologyUploaderProvider retVal = new TerminologyUploaderProvider();
retVal.setContext(fhirContextDstu3());
return retVal;
}

View File

@ -10,7 +10,7 @@ import ca.uhn.fhir.jpa.dao.ISearchParamRegistry;
import ca.uhn.fhir.jpa.dao.r4.SearchParamExtractorR4;
import ca.uhn.fhir.jpa.dao.r4.SearchParamRegistryR4;
import ca.uhn.fhir.jpa.graphql.JpaStorageServices;
import ca.uhn.fhir.jpa.provider.r4.TerminologyUploaderProviderR4;
import ca.uhn.fhir.jpa.provider.TerminologyUploaderProvider;
import ca.uhn.fhir.jpa.term.HapiTerminologySvcR4;
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
import ca.uhn.fhir.jpa.term.IHapiTerminologySvcR4;
@ -133,8 +133,8 @@ public class BaseR4Config extends BaseConfig {
}
@Bean(autowire = Autowire.BY_TYPE)
public TerminologyUploaderProviderR4 terminologyUploaderProvider() {
TerminologyUploaderProviderR4 retVal = new TerminologyUploaderProviderR4();
public TerminologyUploaderProvider terminologyUploaderProvider() {
TerminologyUploaderProvider retVal = new TerminologyUploaderProvider();
retVal.setContext(fhirContextR4());
return retVal;
}

View File

@ -194,7 +194,7 @@ public class FhirResourceDaoValueSetDstu2 extends FhirResourceDaoDstu2<ValueSet>
retVal.setSearchedForSystem(system);
retVal.setFound(true);
if (nextCode.getAbstract() != null) {
retVal.setCodeIsAbstract(nextCode.getAbstract().booleanValue());
retVal.setCodeIsAbstract(nextCode.getAbstract());
}
retVal.setCodeDisplay(nextCode.getDisplay());
retVal.setCodeSystemVersion(nextCode.getVersion());

View File

@ -1,13 +1,12 @@
package ca.uhn.fhir.jpa.dao;
import ca.uhn.fhir.context.support.IContextValidationSupport;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
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.BooleanType;
import org.hl7.fhir.r4.model.Parameters;
import org.hl7.fhir.r4.model.StringType;
import org.hl7.fhir.r4.model.*;
import java.util.List;
@ -48,6 +47,8 @@ public interface IFhirResourceDaoCodeSystem<T extends IBaseResource, CD, CC> ext
private boolean myFound;
private String mySearchedForCode;
private String mySearchedForSystem;
private List<IContextValidationSupport.BaseConceptProperty> myProperties;
/**
* Constructor
*/
@ -111,6 +112,10 @@ public interface IFhirResourceDaoCodeSystem<T extends IBaseResource, CD, CC> ext
myFound = theFound;
}
public void setProperties(List<IContextValidationSupport.BaseConceptProperty> theProperties) {
myProperties = theProperties;
}
public void throwNotFoundIfAppropriate() {
if (isFound() == false) {
throw new ResourceNotFoundException("Unable to find code[" + getSearchedForCode() + "] in system[" + getSearchedForSystem() + "]");
@ -127,6 +132,35 @@ public interface IFhirResourceDaoCodeSystem<T extends IBaseResource, CD, CC> ext
retVal.addParameter().setName("display").setValue(new StringType(getCodeDisplay()));
retVal.addParameter().setName("abstract").setValue(new BooleanType(isCodeIsAbstract()));
if (myProperties != null) {
for (IContextValidationSupport.BaseConceptProperty next : myProperties) {
Parameters.ParametersParameterComponent property = retVal.addParameter().setName("property");
property
.addPart()
.setName("code")
.setValue(new CodeType(next.getPropertyName()));
if (next instanceof IContextValidationSupport.StringConceptProperty) {
IContextValidationSupport.StringConceptProperty prop = (IContextValidationSupport.StringConceptProperty) next;
property
.addPart()
.setName("value")
.setValue(new StringType(prop.getValue()));
} else if (next instanceof IContextValidationSupport.CodingConceptProperty) {
IContextValidationSupport.CodingConceptProperty prop = (IContextValidationSupport.CodingConceptProperty) next;
property
.addPart()
.setName("value")
.setValue(new Coding()
.setSystem(prop.getCodeSystem())
.setCode(prop.getCode())
.setDisplay(prop.getDisplay()));
} else {
throw new IllegalStateException("Don't know how to handle " + next.getClass());
}
}
}
return retVal;
}
}

View File

@ -0,0 +1,37 @@
package ca.uhn.fhir.jpa.dao.data;
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
import ca.uhn.fhir.jpa.entity.TermConcept;
import ca.uhn.fhir.jpa.entity.TermConceptProperty;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.List;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2018 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
public interface ITermConceptPropertyDao extends JpaRepository<TermConceptProperty, Long> {
// nothing
}

View File

@ -52,6 +52,7 @@ import java.util.Date;
import java.util.List;
import java.util.Set;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
public class FhirResourceDaoCodeSystemDstu3 extends FhirResourceDaoDstu3<CodeSystem> implements IFhirResourceDaoCodeSystem<CodeSystem, Coding, CodeableConcept> {
@ -98,7 +99,7 @@ public class FhirResourceDaoCodeSystemDstu3 extends FhirResourceDaoDstu3<CodeSys
public List<IIdType> findCodeSystemIdsContainingSystemAndCode(String theCode, String theSystem) {
List<IIdType> valueSetIds;
Set<Long> ids = searchForIds(new SearchParameterMap(CodeSystem.SP_CODE, new TokenParam(theSystem, theCode)));
valueSetIds = new ArrayList<IIdType>();
valueSetIds = new ArrayList<>();
for (Long next : ids) {
valueSetIds.add(new IdType("CodeSystem", next));
}
@ -128,11 +129,11 @@ public class FhirResourceDaoCodeSystemDstu3 extends FhirResourceDaoDstu3<CodeSys
system = theSystem.getValue();
}
ourLog.info("Looking up {} / {}", system, code);
ourLog.debug("Looking up {} / {}", system, code);
if (myValidationSupport.isCodeSystemSupported(getContext(), system)) {
ourLog.info("Code system {} is supported", system);
ourLog.debug("Code system {} is supported", system);
CodeValidationResult result = myValidationSupport.validateCode(getContext(), system, code, null);
if (result != null) {
@ -142,32 +143,20 @@ public class FhirResourceDaoCodeSystemDstu3 extends FhirResourceDaoDstu3<CodeSys
retVal.setSearchedForCode(code);
retVal.setSearchedForSystem(system);
retVal.setCodeDisplay(result.asConceptDefinition().getDisplay());
retVal.setCodeSystemDisplayName("Unknown");
retVal.setCodeSystemVersion("");
String codeSystemDisplayName = result.getCodeSystemName();
if (isBlank(codeSystemDisplayName)) {
codeSystemDisplayName = "Unknown";
}
retVal.setCodeSystemDisplayName(codeSystemDisplayName);
retVal.setCodeSystemVersion(result.getCodeSystemVersion());
retVal.setProperties(result.getProperties());
return retVal;
}
}
// HapiWorkerContext ctx = new HapiWorkerContext(getContext(), myValidationSupport);
// ValueSetExpander expander = ctx.getExpander();
// ValueSet source = new ValueSet();
// source.getCompose().addInclude().setSystem(system).addConcept().setCode(code);
//
// ValueSetExpansionOutcome expansion;
// try {
// expansion = expander.expand(source);
// } catch (Exception e) {
// throw new InternalErrorException(e);
// }
//
// if (expansion.getValueset() != null) {
// List<ValueSetExpansionContainsComponent> contains = expansion.getValueset().getExpansion().getContains();
// LookupCodeResult result = lookup(contains, system, code);
// if (result != null) {
// return result;
// }
// }
}
// We didn't find it..
@ -229,7 +218,7 @@ public class FhirResourceDaoCodeSystemDstu3 extends FhirResourceDaoDstu3<CodeSys
persCs.setResource(retVal);
persCs.getConcepts().addAll(toPersistedConcepts(cs.getConcept(), persCs));
ourLog.info("Code system has {} concepts", persCs.getConcepts().size());
myTerminologySvc.storeNewCodeSystemVersion(codeSystemResourcePid, codeSystemUrl, persCs);
myTerminologySvc.storeNewCodeSystemVersion(codeSystemResourcePid, codeSystemUrl, cs.getName(), persCs);
}
}

View File

@ -52,6 +52,7 @@ import java.util.Date;
import java.util.List;
import java.util.Set;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
public class FhirResourceDaoCodeSystemR4 extends FhirResourceDaoR4<CodeSystem> implements IFhirResourceDaoCodeSystem<CodeSystem, Coding, CodeableConcept> {
@ -67,30 +68,6 @@ public class FhirResourceDaoCodeSystemR4 extends FhirResourceDaoR4<CodeSystem> i
@Autowired
private ValidationSupportChain myValidationSupport;
// private LookupCodeResult lookup(List<ValueSetExpansionContainsComponent> theContains, String theSystem, String theCode) {
// for (ValueSetExpansionContainsComponent nextCode : theContains) {
//
// String system = nextCode.getSystem();
// String code = nextCode.getCode();
// if (theSystem.equals(system) && theCode.equals(code)) {
// LookupCodeResult retVal = new LookupCodeResult();
// retVal.setSearchedForCode(code);
// retVal.setSearchedForSystem(system);
// retVal.setFound(true);
// if (nextCode.getAbstractElement().getValue() != null) {
// retVal.setCodeIsAbstract(nextCode.getAbstractElement().booleanValue());
// }
// retVal.setCodeDisplay(nextCode.getDisplay());
// retVal.setCodeSystemVersion(nextCode.getVersion());
// retVal.setCodeSystemDisplayName("Unknown"); // TODO: implement
// return retVal;
// }
//
// }
//
// return null;
// }
@Override
public List<IIdType> findCodeSystemIdsContainingSystemAndCode(String theCode, String theSystem) {
List<IIdType> valueSetIds;
@ -139,32 +116,20 @@ public class FhirResourceDaoCodeSystemR4 extends FhirResourceDaoR4<CodeSystem> i
retVal.setSearchedForCode(code);
retVal.setSearchedForSystem(system);
retVal.setCodeDisplay(result.asConceptDefinition().getDisplay());
retVal.setCodeSystemDisplayName("Unknown");
retVal.setCodeSystemVersion("");
String codeSystemDisplayName = result.getCodeSystemName();
if (isBlank(codeSystemDisplayName)) {
codeSystemDisplayName = "Unknown";
}
retVal.setCodeSystemDisplayName(codeSystemDisplayName);
retVal.setCodeSystemVersion(result.getCodeSystemVersion());
retVal.setProperties(result.getProperties());
return retVal;
}
}
// HapiWorkerContext ctx = new HapiWorkerContext(getContext(), myValidationSupport);
// ValueSetExpander expander = ctx.getExpander();
// ValueSet source = new ValueSet();
// source.getCompose().addInclude().setSystem(system).addConcept().setCode(code);
//
// ValueSetExpansionOutcome expansion;
// try {
// expansion = expander.expand(source);
// } catch (Exception e) {
// throw new InternalErrorException(e);
// }
//
// if (expansion.getValueset() != null) {
// List<ValueSetExpansionContainsComponent> contains = expansion.getValueset().getExpansion().getContains();
// LookupCodeResult result = lookup(contains, system, code);
// if (result != null) {
// return result;
// }
// }
}
// We didn't find it..
@ -228,7 +193,7 @@ public class FhirResourceDaoCodeSystemR4 extends FhirResourceDaoR4<CodeSystem> i
persCs.setResource(retVal);
persCs.getConcepts().addAll(toPersistedConcepts(cs.getConcept(), persCs));
ourLog.info("Code system has {} concepts", persCs.getConcepts().size());
myTerminologySvc.storeNewCodeSystemVersion(codeSystemResourcePid, codeSystemUrl, persCs);
myTerminologySvc.storeNewCodeSystemVersion(codeSystemResourcePid, codeSystemUrl, cs.getName(), persCs);
}

View File

@ -23,6 +23,8 @@ package ca.uhn.fhir.jpa.entity;
import javax.persistence.*;
import java.io.Serializable;
import static org.apache.commons.lang3.StringUtils.left;
//@formatter:off
@Table(name = "TRM_CODESYSTEM", uniqueConstraints = {
@UniqueConstraint(name = "IDX_CS_CODESYSTEM", columnNames = {"CODE_SYSTEM_URI"})
@ -31,6 +33,7 @@ import java.io.Serializable;
//@formatter:on
public class TermCodeSystem implements Serializable {
private static final long serialVersionUID = 1L;
public static final int CS_NAME_LENGTH = 200;
@Column(name = "CODE_SYSTEM_URI", nullable = false)
private String myCodeSystemUri;
@ -48,11 +51,17 @@ public class TermCodeSystem implements Serializable {
private ResourceTable myResource;
@Column(name = "RES_ID", insertable = false, updatable = false)
private Long myResourcePid;
@Column(name = "CS_NAME", nullable = true)
private String myName;
public String getCodeSystemUri() {
return myCodeSystemUri;
}
public String getName() {
return myName;
}
public void setCodeSystemUri(String theCodeSystemUri) {
myCodeSystemUri = theCodeSystemUri;
}
@ -73,6 +82,10 @@ public class TermCodeSystem implements Serializable {
return myResource;
}
public void setName(String theName) {
myName = left(theName, CS_NAME_LENGTH);
}
public void setResource(ResourceTable theResource) {
myResource = theResource;
}

View File

@ -1,5 +1,6 @@
package ca.uhn.fhir.jpa.entity;
import ca.uhn.fhir.context.support.IContextValidationSupport;
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum;
import ca.uhn.fhir.jpa.search.DeferConceptIndexingInterceptor;
import org.apache.commons.lang3.Validate;
@ -75,7 +76,7 @@ public class TermConcept implements Serializable {
})
private String myDisplay;
@OneToMany(mappedBy = "myConcept")
@OneToMany(mappedBy = "myConcept", orphanRemoval = true)
@Field
@FieldBridge(impl = TermConceptPropertyFieldBridge.class)
private Collection<TermConceptProperty> myProperties;
@ -130,7 +131,7 @@ public class TermConcept implements Serializable {
property.setType(thePropertyType);
property.setKey(thePropertyName);
property.setValue(thePropertyValue);
getStringProperties().add(property);
getProperties().add(property);
return property;
}
@ -223,7 +224,7 @@ public class TermConcept implements Serializable {
return myParents;
}
public Collection<TermConceptProperty> getStringProperties() {
public Collection<TermConceptProperty> getProperties() {
if (myProperties == null) {
myProperties = new ArrayList<>();
}
@ -232,7 +233,7 @@ public class TermConcept implements Serializable {
public List<String> getStringProperties(String thePropertyName) {
List<String> retVal = new ArrayList<>();
for (TermConceptProperty next : getStringProperties()) {
for (TermConceptProperty next : getProperties()) {
if (thePropertyName.equals(next.getKey())) {
if (next.getType() == TermConceptPropertyTypeEnum.STRING) {
retVal.add(next.getValue());
@ -244,7 +245,7 @@ public class TermConcept implements Serializable {
public List<Coding> getCodingProperties(String thePropertyName) {
List<Coding> retVal = new ArrayList<>();
for (TermConceptProperty next : getStringProperties()) {
for (TermConceptProperty next : getProperties()) {
if (thePropertyName.equals(next.getKey())) {
if (next.getType() == TermConceptPropertyTypeEnum.CODING) {
Coding coding = new Coding();
@ -334,4 +335,20 @@ public class TermConcept implements Serializable {
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE).append("code", myCode).append("display", myDisplay).build();
}
public List<IContextValidationSupport.BaseConceptProperty> toValidationProperties() {
List<IContextValidationSupport.BaseConceptProperty> retVal = new ArrayList<>();
for (TermConceptProperty next : getProperties()) {
switch (next.getType()) {
case STRING:
retVal.add(new IContextValidationSupport.StringConceptProperty(next.getKey(), next.getValue()));
break;
case CODING:
retVal.add(new IContextValidationSupport.CodingConceptProperty(next.getKey(), next.getCodeSystem(), next.getValue(), next.getDisplay()));
break;
default:
throw new IllegalStateException("Don't know how to handle " + next.getType());
}
}
return retVal;
}
}

View File

@ -1,4 +1,4 @@
package ca.uhn.fhir.jpa.provider.dstu3;
package ca.uhn.fhir.jpa.provider;
/*
* #%L
@ -20,81 +20,86 @@ package ca.uhn.fhir.jpa.provider.dstu3;
* #L%
*/
import static org.apache.commons.lang3.StringUtils.defaultString;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.io.IOUtils;
import org.hl7.fhir.dstu3.model.*;
import org.springframework.beans.factory.annotation.Autowired;
import ca.uhn.fhir.jpa.provider.BaseJpaProvider;
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc.UploadStatistics;
import ca.uhn.fhir.rest.annotation.Operation;
import ca.uhn.fhir.rest.annotation.OperationParam;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import org.hl7.fhir.r4.model.IntegerType;
import org.hl7.fhir.r4.model.Parameters;
import org.hl7.fhir.r4.model.StringType;
import org.springframework.beans.factory.annotation.Autowired;
public class TerminologyUploaderProviderDstu3 extends BaseJpaProvider {
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import static org.apache.commons.lang3.StringUtils.defaultString;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
public class TerminologyUploaderProvider extends BaseJpaProvider {
public static final String UPLOAD_EXTERNAL_CODE_SYSTEM = "$upload-external-code-system";
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TerminologyUploaderProviderDstu3.class);
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TerminologyUploaderProvider.class);
@Autowired
private IHapiTerminologyLoaderSvc myTerminologyLoaderSvc;
//@formatter:off
@Operation(name = UPLOAD_EXTERNAL_CODE_SYSTEM, idempotent = false, returnParameters= {
@OperationParam(name="conceptCount", type=IntegerType.class, min=1)
})
public Parameters uploadExternalCodeSystem(
HttpServletRequest theServletRequest,
@OperationParam(name="url", min=1) UriType theUrl,
@OperationParam(name="package", min=0) Attachment thePackage,
@OperationParam(name="localfile", min=0, max=OperationParam.MAX_UNLIMITED) List<StringType> theLocalFile,
@OperationParam(name="url", min=1) StringParam theCodeSystemUrl,
@OperationParam(name="localfile", min=1, max=OperationParam.MAX_UNLIMITED) List<StringType> theLocalFile,
RequestDetails theRequestDetails
) {
//@formatter:on
startRequest(theServletRequest);
try {
List<byte[]> data = new ArrayList<byte[]>();
List<IHapiTerminologyLoaderSvc.FileDescriptor> localFiles = new ArrayList<>();
if (theLocalFile != null && theLocalFile.size() > 0) {
for (StringType nextLocalFile : theLocalFile) {
if (isNotBlank(nextLocalFile.getValue())) {
ourLog.info("Reading in local file: {}", nextLocalFile.getValue());
try {
byte[] nextData = IOUtils.toByteArray(new FileInputStream(nextLocalFile.getValue()));
data.add(nextData);
} catch (IOException e) {
throw new InternalErrorException(e);
File nextFile = new File(nextLocalFile.getValue());
if (!nextFile.exists() || nextFile.isFile()) {
throw new InvalidRequestException("Unknown file: " +nextFile.getName());
}
localFiles.add(new IHapiTerminologyLoaderSvc.FileDescriptor() {
@Override
public String getFilename() {
return nextFile.getAbsolutePath();
}
@Override
public InputStream getInputStream() {
try {
return new FileInputStream(nextFile);
} catch (FileNotFoundException theE) {
throw new InternalErrorException(theE);
}
}
});
}
}
} else if (thePackage == null || thePackage.getData() == null || thePackage.getData().length == 0) {
throw new InvalidRequestException("No 'localfile' or 'package' parameter, or package had no data");
} else {
data = new ArrayList<byte[]>();
data.add(thePackage.getData());
thePackage.setData(null);
}
String url = theUrl != null ? theUrl.getValueAsString() : null;
String url = theCodeSystemUrl != null ? theCodeSystemUrl.getValue() : null;
url = defaultString(url);
UploadStatistics stats;
if (IHapiTerminologyLoaderSvc.SCT_URL.equals(url)) {
stats = myTerminologyLoaderSvc.loadSnomedCt((data), theRequestDetails);
} else if (IHapiTerminologyLoaderSvc.LOINC_URL.equals(url)) {
stats = myTerminologyLoaderSvc.loadLoinc((data), theRequestDetails);
if (IHapiTerminologyLoaderSvc.SCT_URI.equals(url)) {
stats = myTerminologyLoaderSvc.loadSnomedCt(localFiles, theRequestDetails);
} else if (IHapiTerminologyLoaderSvc.LOINC_URI.equals(url)) {
stats = myTerminologyLoaderSvc.loadLoinc(localFiles, theRequestDetails);
} else {
throw new InvalidRequestException("Unknown URL: " + url);
}

View File

@ -1,111 +0,0 @@
package ca.uhn.fhir.jpa.provider.r4;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2018 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import static org.apache.commons.lang3.StringUtils.defaultString;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.io.IOUtils;
import org.hl7.fhir.r4.model.*;
import org.springframework.beans.factory.annotation.Autowired;
import ca.uhn.fhir.jpa.provider.BaseJpaProvider;
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc.UploadStatistics;
import ca.uhn.fhir.rest.annotation.Operation;
import ca.uhn.fhir.rest.annotation.OperationParam;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
public class TerminologyUploaderProviderR4 extends BaseJpaProvider {
public static final String UPLOAD_EXTERNAL_CODE_SYSTEM = "$upload-external-code-system";
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TerminologyUploaderProviderR4.class);
@Autowired
private IHapiTerminologyLoaderSvc myTerminologyLoaderSvc;
//@formatter:off
@Operation(name = UPLOAD_EXTERNAL_CODE_SYSTEM, idempotent = false, returnParameters= {
@OperationParam(name="conceptCount", type=IntegerType.class, min=1)
})
public Parameters uploadExternalCodeSystem(
HttpServletRequest theServletRequest,
@OperationParam(name="url", min=1) UriType theUrl,
@OperationParam(name="package", min=0) Attachment thePackage,
@OperationParam(name="localfile", min=0, max=OperationParam.MAX_UNLIMITED) List<StringType> theLocalFile,
RequestDetails theRequestDetails
) {
//@formatter:on
startRequest(theServletRequest);
try {
List<byte[]> data = new ArrayList<byte[]>();
if (theLocalFile != null && theLocalFile.size() > 0) {
for (StringType nextLocalFile : theLocalFile) {
if (isNotBlank(nextLocalFile.getValue())) {
ourLog.info("Reading in local file: {}", nextLocalFile.getValue());
try {
byte[] nextData = IOUtils.toByteArray(new FileInputStream(nextLocalFile.getValue()));
data.add(nextData);
} catch (IOException e) {
throw new InternalErrorException(e);
}
}
}
} else if (thePackage == null || thePackage.getData() == null || thePackage.getData().length == 0) {
throw new InvalidRequestException("No 'localfile' or 'package' parameter, or package had no data");
} else {
data = new ArrayList<byte[]>();
data.add(thePackage.getData());
thePackage.setData(null);
}
String url = theUrl != null ? theUrl.getValueAsString() : null;
url = defaultString(url);
UploadStatistics stats;
if (IHapiTerminologyLoaderSvc.SCT_URL.equals(url)) {
stats = myTerminologyLoaderSvc.loadSnomedCt((data), theRequestDetails);
} else if (IHapiTerminologyLoaderSvc.LOINC_URL.equals(url)) {
stats = myTerminologyLoaderSvc.loadLoinc((data), theRequestDetails);
} else {
throw new InvalidRequestException("Unknown URL: " + url);
}
Parameters retVal = new Parameters();
retVal.addParameter().setName("conceptCount").setValue(new IntegerType(stats.getConceptCount()));
return retVal;
} finally {
endRequest(theServletRequest);
}
}
}

View File

@ -24,10 +24,7 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoCodeSystem;
import ca.uhn.fhir.jpa.dao.data.ITermCodeSystemDao;
import ca.uhn.fhir.jpa.dao.data.ITermCodeSystemVersionDao;
import ca.uhn.fhir.jpa.dao.data.ITermConceptDao;
import ca.uhn.fhir.jpa.dao.data.ITermConceptParentChildLinkDao;
import ca.uhn.fhir.jpa.dao.data.*;
import ca.uhn.fhir.jpa.entity.*;
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum;
import ca.uhn.fhir.rest.api.server.RequestDetails;
@ -79,6 +76,8 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc
@Autowired
protected ITermConceptDao myConceptDao;
@Autowired
protected ITermConceptPropertyDao myConceptPropertyDao;
@Autowired
protected FhirContext myContext;
@PersistenceContext(type = PersistenceContextType.TRANSACTION)
protected EntityManager myEntityManager;
@ -430,6 +429,10 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc
}
}
for (TermConceptProperty next : theConcept.getProperties()){
myConceptPropertyDao.save(next);
}
}
private void populateVersion(TermConcept theNext, TermCodeSystemVersion theCodeSystemVersion) {
@ -616,7 +619,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void storeNewCodeSystemVersion(Long theCodeSystemResourcePid, String theSystemUri, TermCodeSystemVersion theCodeSystemVersion) {
public void storeNewCodeSystemVersion(Long theCodeSystemResourcePid, String theSystemUri, String theSystemName, TermCodeSystemVersion theCodeSystemVersion) {
ourLog.info("Storing code system");
ValidateUtil.isTrueOrThrowInvalidRequest(theCodeSystemVersion.getResource() != null, "No resource supplied");
@ -655,6 +658,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc
}
codeSystem.setResource(theCodeSystemVersion.getResource());
codeSystem.setCodeSystemUri(theSystemUri);
codeSystem.setName(theSystemName);
myCodeSystemDao.save(codeSystem);
} else {
if (!ObjectUtil.equals(codeSystem.getResource().getId(), theCodeSystemVersion.getResource().getId())) {
@ -721,7 +725,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc
ourLog.info("CodeSystem resource has ID: {}", csId.getValue());
theCodeSystemVersion.setResource(resource);
storeNewCodeSystemVersion(codeSystemResourcePid, theCodeSystemResource.getUrl(), theCodeSystemVersion);
storeNewCodeSystemVersion(codeSystemResourcePid, theCodeSystemResource.getUrl(), theCodeSystemResource.getName(), theCodeSystemVersion);
for (ValueSet nextValueSet : theValueSets) {
createOrUpdateValueSet(nextValueSet, theRequestDetails);

View File

@ -235,7 +235,10 @@ public class HapiTerminologySvcDstu3 extends BaseHapiTerminologySvcImpl implemen
ConceptDefinitionComponent def = new ConceptDefinitionComponent();
def.setCode(code.getCode());
def.setDisplay(code.getDisplay());
return new CodeValidationResult(def);
CodeValidationResult retVal = new CodeValidationResult(def);
retVal.setProperties(code.toValidationProperties());
retVal.setCodeSystemName(code.getCodeSystem().get);
return retVal;
}
return new CodeValidationResult(IssueSeverity.ERROR, "Unknown code {" + theCodeSystem + "}" + theCode);

View File

@ -103,7 +103,7 @@ public class HapiTerminologySvcR4 extends BaseHapiTerminologySvcImpl implements
@Override
protected void createOrUpdateConceptMap(org.hl7.fhir.r4.model.ConceptMap theConceptMap, RequestDetails theRequestDetails) {
String matchUrl = "ConceptMap?url=" + UrlUtil.escapeUrlParam(theConceptMap.getUrl());
myConceptMapResourceDao.update(theConceptMap, matchUrl, theRequestDetails).getId();
myConceptMapResourceDao.update(theConceptMap, matchUrl, theRequestDetails);
}
@Override
@ -201,10 +201,12 @@ public class HapiTerminologySvcR4 extends BaseHapiTerminologySvcImpl implements
ConceptDefinitionComponent def = new ConceptDefinitionComponent();
def.setCode(code.getCode());
def.setDisplay(code.getDisplay());
return new CodeValidationResult(def);
CodeValidationResult retVal = new CodeValidationResult(def);
retVal.setProperties(code.toValidationProperties());
return retVal;
}
return new CodeValidationResult(IssueSeverity.ERROR, "Unkonwn code {" + theCodeSystem + "}" + theCode);
return new CodeValidationResult(IssueSeverity.ERROR, "Unknown code {" + theCodeSystem + "}" + theCode);
}
}

View File

@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.term;
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -20,20 +20,30 @@ package ca.uhn.fhir.jpa.term;
* #L%
*/
import java.util.List;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import java.io.InputStream;
import java.util.List;
public interface IHapiTerminologyLoaderSvc {
String LOINC_URL = "http://loinc.org";
String SCT_URL = "http://snomed.info/sct";
String LOINC_URI = "http://loinc.org";
String SCT_URI = "http://snomed.info/sct";
String IEEE_11073_10101_URI = "urn:iso:std:iso:11073:10101";
UploadStatistics loadLoinc(List<byte[]> theZipBytes, RequestDetails theRequestDetails);
UploadStatistics loadLoinc(List<FileDescriptor> theFiles, RequestDetails theRequestDetails);
UploadStatistics loadSnomedCt(List<byte[]> theZipBytes, RequestDetails theRequestDetails);
UploadStatistics loadSnomedCt(List<FileDescriptor> theFiles, RequestDetails theRequestDetails);
public static class UploadStatistics {
interface FileDescriptor {
String getFilename();
InputStream getInputStream();
}
class UploadStatistics {
private final int myConceptCount;
public UploadStatistics(int theConceptCount) {

View File

@ -57,7 +57,7 @@ public interface IHapiTerminologySvc {
*/
void setProcessDeferred(boolean theProcessDeferred);
void storeNewCodeSystemVersion(Long theCodeSystemResourcePid, String theSystemUri, TermCodeSystemVersion theCodeSytemVersion);
void storeNewCodeSystemVersion(Long theCodeSystemResourcePid, String theSystemUri, String theSystemName, TermCodeSystemVersion theCodeSytemVersion);
boolean supportsSystem(String theCodeSystem);

View File

@ -11,13 +11,14 @@ import ca.uhn.fhir.jpa.term.snomedct.SctHandlerRelationship;
import ca.uhn.fhir.jpa.util.Counter;
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.rest.server.exceptions.UnprocessableEntityException;
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.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.input.BOMInputStream;
import org.apache.commons.lang3.ObjectUtils;
@ -69,8 +70,11 @@ public class TerminologyLoaderSvcImpl implements IHapiTerminologyLoaderSvc {
public static final String LOINC_PART_LINK_FILE = "LoincPartLink_Beta_1.csv";
public static final String LOINC_PART_RELATED_CODE_MAPPING_FILE = "PartRelatedCodeMapping_Beta_1.csv";
public static final String LOINC_RSNA_PLAYBOOK_FILE = "LoincRsnaRadiologyPlaybook.csv";
public static final String TOP2000_COMMON_LAB_RESULTS_US_FILE = "Top2000CommonLabResultsUS.csv";
public static final String TOP2000_COMMON_LAB_RESULTS_SI_FILE = "Top2000CommonLabResultsSI.csv";
public static final String LOINC_TOP2000_COMMON_LAB_RESULTS_US_FILE = "Top2000CommonLabResultsUS.csv";
public static final String LOINC_TOP2000_COMMON_LAB_RESULTS_SI_FILE = "Top2000CommonLabResultsSI.csv";
public static final String LOINC_UNIVERSAL_LAB_ORDER_VALUESET_FILE = "LoincUniversalLabOrdersValueSet.csv";
public static final String LOINC_IEEE_MEDICAL_DEVICE_CODE_MAPPING_TABLE_CSV = "LoincIeeeMedicalDeviceCodeMappingTable.csv";
public static final String LOINC_IMAGING_DOCUMENT_CODES_FILE = "ImagingDocumentCodes.csv";
private static final int LOG_INCREMENT = 100000;
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TerminologyLoaderSvcImpl.class);
@Autowired
@ -113,85 +117,91 @@ public class TerminologyLoaderSvcImpl implements IHapiTerminologyLoaderSvc {
}
private void iterateOverZipFile(List<byte[]> theZipBytes, String fileNamePart, IRecordHandler handler, char theDelimiter, QuoteMode theQuoteMode) {
boolean found = false;
private void iterateOverZipFile(LoadedFileDescriptors theDescriptors, String theFileNamePart, IRecordHandler theHandler, char theDelimiter, QuoteMode theQuoteMode) {
for (byte[] nextZipBytes : theZipBytes) {
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new ByteArrayInputStream(nextZipBytes)));
try {
for (ZipEntry nextEntry; (nextEntry = zis.getNextEntry()) != null; ) {
for (FileDescriptor nextZipBytes : theDescriptors.getUncompressedFileDescriptors()) {
String nextFilename = nextZipBytes.getFilename();
if (nextFilename.contains(theFileNamePart)) {
ourLog.info("Processing file {}", nextFilename);
String nextFilename = nextEntry.getName();
if (nextFilename.contains(fileNamePart)) {
ourLog.info("Processing file {}", nextFilename);
found = true;
Reader reader;
CSVParser parsed;
try {
reader = new InputStreamReader(nextZipBytes.getInputStream(), Charsets.UTF_8);
CSVFormat format = CSVFormat.newFormat(theDelimiter).withFirstRecordAsHeader();
if (theQuoteMode != null) {
format = format.withQuote('"').withQuoteMode(theQuoteMode);
}
parsed = new CSVParser(reader, format);
Iterator<CSVRecord> iter = parsed.iterator();
ourLog.debug("Header map: {}", parsed.getHeaderMap());
Reader reader;
CSVParser parsed;
try {
reader = new InputStreamReader(new BOMInputStream(zis), Charsets.UTF_8);
CSVFormat format = CSVFormat.newFormat(theDelimiter).withFirstRecordAsHeader();
if (theQuoteMode != null) {
format = format.withQuote('"').withQuoteMode(theQuoteMode);
}
parsed = new CSVParser(reader, format);
Iterator<CSVRecord> iter = parsed.iterator();
ourLog.debug("Header map: {}", parsed.getHeaderMap());
int count = 0;
int logIncrement = LOG_INCREMENT;
int nextLoggedCount = 0;
while (iter.hasNext()) {
CSVRecord nextRecord = iter.next();
handler.accept(nextRecord);
count++;
if (count >= nextLoggedCount) {
ourLog.info(" * Processed {} records in {}", count, nextFilename);
nextLoggedCount += logIncrement;
}
}
} catch (IOException e) {
throw new InternalErrorException(e);
int count = 0;
int nextLoggedCount = 0;
while (iter.hasNext()) {
CSVRecord nextRecord = iter.next();
theHandler.accept(nextRecord);
count++;
if (count >= nextLoggedCount) {
ourLog.info(" * Processed {} records in {}", count, nextFilename);
nextLoggedCount += LOG_INCREMENT;
}
}
} catch (IOException e) {
throw new InternalErrorException(e);
}
} catch (IOException e) {
throw new InternalErrorException(e);
} finally {
IOUtils.closeQuietly(zis);
}
}
// This should always be true, but just in case we've introduced a bug...
Validate.isTrue(found);
}
@Override
public UploadStatistics loadLoinc(List<byte[]> theZipBytes, RequestDetails theRequestDetails) {
List<String> expectedFilenameFragments = Arrays.asList(
public UploadStatistics loadLoinc(List<FileDescriptor> theFiles, RequestDetails theRequestDetails) {
LoadedFileDescriptors descriptors = new LoadedFileDescriptors(theFiles);
List<String> mandatoryFilenameFragments = Arrays.asList(
LOINC_FILE,
LOINC_HIERARCHY_FILE);
descriptors.verifyMandatoryFilesExist(mandatoryFilenameFragments);
verifyMandatoryFilesExist(theZipBytes, expectedFilenameFragments);
List<String> optionalFilenameFragments = Arrays.asList(
LOINC_ANSWERLIST_FILE,
LOINC_ANSWERLIST_LINK_FILE,
LOINC_PART_FILE,
LOINC_PART_LINK_FILE,
LOINC_PART_RELATED_CODE_MAPPING_FILE,
LOINC_DOCUMENT_ONTOLOGY_FILE,
LOINC_RSNA_PLAYBOOK_FILE,
LOINC_TOP2000_COMMON_LAB_RESULTS_US_FILE,
LOINC_TOP2000_COMMON_LAB_RESULTS_SI_FILE,
LOINC_UNIVERSAL_LAB_ORDER_VALUESET_FILE,
LOINC_IEEE_MEDICAL_DEVICE_CODE_MAPPING_TABLE_CSV,
LOINC_IMAGING_DOCUMENT_CODES_FILE
);
descriptors.verifyOptionalFilesExist(optionalFilenameFragments);
ourLog.info("Beginning LOINC processing");
return processLoincFiles(theZipBytes, theRequestDetails);
return processLoincFiles(descriptors, theRequestDetails);
}
@Override
public UploadStatistics loadSnomedCt(List<byte[]> theZipBytes, RequestDetails theRequestDetails) {
List<String> expectedFilenameFragments = Arrays.asList(SCT_FILE_DESCRIPTION, SCT_FILE_RELATIONSHIP, SCT_FILE_CONCEPT);
public UploadStatistics loadSnomedCt(List<FileDescriptor> theFiles, RequestDetails theRequestDetails) {
LoadedFileDescriptors descriptors = new LoadedFileDescriptors(theFiles);
verifyMandatoryFilesExist(theZipBytes, expectedFilenameFragments);
List<String> expectedFilenameFragments = Arrays.asList(
SCT_FILE_DESCRIPTION,
SCT_FILE_RELATIONSHIP,
SCT_FILE_CONCEPT);
descriptors.verifyMandatoryFilesExist(expectedFilenameFragments);
ourLog.info("Beginning SNOMED CT processing");
return processSnomedCtFiles(theZipBytes, theRequestDetails);
return processSnomedCtFiles(descriptors, theRequestDetails);
}
UploadStatistics processLoincFiles(List<byte[]> theZipBytes, RequestDetails theRequestDetails) {
UploadStatistics processLoincFiles(LoadedFileDescriptors theDescriptors, RequestDetails theRequestDetails) {
final TermCodeSystemVersion codeSystemVersion = new TermCodeSystemVersion();
final Map<String, TermConcept> code2concept = new HashMap<>();
final List<ValueSet> valueSets = new ArrayList<>();
@ -216,49 +226,61 @@ public class TerminologyLoaderSvcImpl implements IHapiTerminologyLoaderSvc {
// Loinc Codes
handler = new LoincHandler(codeSystemVersion, code2concept, propertyNames);
iterateOverZipFile(theZipBytes, LOINC_FILE, handler, ',', QuoteMode.NON_NUMERIC);
iterateOverZipFile(theDescriptors, LOINC_FILE, handler, ',', QuoteMode.NON_NUMERIC);
// Loinc Hierarchy
handler = new LoincHierarchyHandler(codeSystemVersion, code2concept);
iterateOverZipFile(theZipBytes, LOINC_HIERARCHY_FILE, handler, ',', QuoteMode.NON_NUMERIC);
iterateOverZipFile(theDescriptors, LOINC_HIERARCHY_FILE, handler, ',', QuoteMode.NON_NUMERIC);
// Answer lists (ValueSets of potential answers/values for loinc "questions")
handler = new LoincAnswerListHandler(codeSystemVersion, code2concept, propertyNames, valueSets);
iterateOverZipFile(theZipBytes, LOINC_ANSWERLIST_FILE, handler, ',', QuoteMode.NON_NUMERIC);
iterateOverZipFile(theDescriptors, LOINC_ANSWERLIST_FILE, handler, ',', QuoteMode.NON_NUMERIC);
// Answer list links (connects loinc observation codes to answerlist codes)
handler = new LoincAnswerListLinkHandler(code2concept, valueSets);
iterateOverZipFile(theZipBytes, LOINC_ANSWERLIST_LINK_FILE, handler, ',', QuoteMode.NON_NUMERIC);
iterateOverZipFile(theDescriptors, LOINC_ANSWERLIST_LINK_FILE, handler, ',', QuoteMode.NON_NUMERIC);
// Part file
handler = new LoincPartHandler(codeSystemVersion, code2concept);
iterateOverZipFile(theZipBytes, LOINC_PART_FILE, handler, ',', QuoteMode.NON_NUMERIC);
iterateOverZipFile(theDescriptors, LOINC_PART_FILE, handler, ',', QuoteMode.NON_NUMERIC);
// Part link file
handler = new LoincPartLinkHandler(codeSystemVersion, code2concept);
iterateOverZipFile(theZipBytes, LOINC_PART_LINK_FILE, handler, ',', QuoteMode.NON_NUMERIC);
iterateOverZipFile(theDescriptors, LOINC_PART_LINK_FILE, handler, ',', QuoteMode.NON_NUMERIC);
// Part related code mapping
handler = new LoincPartRelatedCodeMappingHandler(codeSystemVersion, code2concept, conceptMaps);
iterateOverZipFile(theZipBytes, LOINC_PART_RELATED_CODE_MAPPING_FILE, handler, ',', QuoteMode.NON_NUMERIC);
handler = new LoincPartRelatedCodeMappingHandler(codeSystemVersion, code2concept, valueSets, conceptMaps);
iterateOverZipFile(theDescriptors, LOINC_PART_RELATED_CODE_MAPPING_FILE, handler, ',', QuoteMode.NON_NUMERIC);
// Document Ontology File
handler = new LoincDocumentOntologyHandler(codeSystemVersion, code2concept, propertyNames, valueSets);
iterateOverZipFile(theZipBytes, LOINC_DOCUMENT_ONTOLOGY_FILE, handler, ',', QuoteMode.NON_NUMERIC);
handler = new LoincDocumentOntologyHandler(codeSystemVersion, code2concept, propertyNames, valueSets, conceptMaps);
iterateOverZipFile(theDescriptors, LOINC_DOCUMENT_ONTOLOGY_FILE, handler, ',', QuoteMode.NON_NUMERIC);
// RSNA Playbook file
handler = new LoincRsnaPlaybookHandler(codeSystemVersion, code2concept, propertyNames, valueSets, conceptMaps);
iterateOverZipFile(theZipBytes, LOINC_RSNA_PLAYBOOK_FILE, handler, ',', QuoteMode.NON_NUMERIC);
iterateOverZipFile(theDescriptors, LOINC_RSNA_PLAYBOOK_FILE, handler, ',', QuoteMode.NON_NUMERIC);
// Top 2000 Codes - US
handler = new LoincTop2000LabResultsUsHandler(code2concept, valueSets);
iterateOverZipFile(theZipBytes, TOP2000_COMMON_LAB_RESULTS_US_FILE, handler, ',', QuoteMode.NON_NUMERIC);
handler = new LoincTop2000LabResultsUsHandler(code2concept, valueSets, conceptMaps);
iterateOverZipFile(theDescriptors, LOINC_TOP2000_COMMON_LAB_RESULTS_US_FILE, handler, ',', QuoteMode.NON_NUMERIC);
// Top 2000 Codes - SI
handler = new LoincTop2000LabResultsSiHandler(code2concept, valueSets);
iterateOverZipFile(theZipBytes, TOP2000_COMMON_LAB_RESULTS_SI_FILE, handler, ',', QuoteMode.NON_NUMERIC);
handler = new LoincTop2000LabResultsSiHandler(code2concept, valueSets, conceptMaps);
iterateOverZipFile(theDescriptors, LOINC_TOP2000_COMMON_LAB_RESULTS_SI_FILE, handler, ',', QuoteMode.NON_NUMERIC);
theZipBytes.clear();
// Universal Lab Order ValueSet
handler = new LoincUniversalOrderSetHandler(code2concept, valueSets, conceptMaps);
iterateOverZipFile(theDescriptors, LOINC_UNIVERSAL_LAB_ORDER_VALUESET_FILE, handler, ',', QuoteMode.NON_NUMERIC);
// IEEE Medical Device Codes
handler = new LoincIeeeMedicalDeviceCodeHandler(code2concept, valueSets, conceptMaps);
iterateOverZipFile(theDescriptors, LOINC_IEEE_MEDICAL_DEVICE_CODE_MAPPING_TABLE_CSV, handler, ',', QuoteMode.NON_NUMERIC);
// Imaging Document Codes
handler = new LoincImagingDocumentCodeHandler(code2concept, valueSets, conceptMaps);
iterateOverZipFile(theDescriptors, LOINC_IMAGING_DOCUMENT_CODES_FILE, handler, ',', QuoteMode.NON_NUMERIC);
IOUtils.closeQuietly(theDescriptors);
for (Entry<String, TermConcept> next : code2concept.entrySet()) {
TermConcept nextConcept = next.getValue();
@ -277,34 +299,32 @@ public class TerminologyLoaderSvcImpl implements IHapiTerminologyLoaderSvc {
return new UploadStatistics(conceptCount);
}
UploadStatistics processSnomedCtFiles(List<byte[]> theZipBytes, RequestDetails theRequestDetails) {
private UploadStatistics processSnomedCtFiles(LoadedFileDescriptors theDescriptors, RequestDetails theRequestDetails) {
final TermCodeSystemVersion codeSystemVersion = new TermCodeSystemVersion();
final Map<String, TermConcept> id2concept = new HashMap<>();
final Map<String, TermConcept> code2concept = new HashMap<>();
final Set<String> validConceptIds = new HashSet<>();
IRecordHandler handler = new SctHandlerConcept(validConceptIds);
iterateOverZipFile(theZipBytes, SCT_FILE_CONCEPT, handler, '\t', null);
iterateOverZipFile(theDescriptors, SCT_FILE_CONCEPT, handler, '\t', null);
ourLog.info("Have {} valid concept IDs", validConceptIds.size());
handler = new SctHandlerDescription(validConceptIds, code2concept, id2concept, codeSystemVersion);
iterateOverZipFile(theZipBytes, SCT_FILE_DESCRIPTION, handler, '\t', null);
iterateOverZipFile(theDescriptors, SCT_FILE_DESCRIPTION, handler, '\t', null);
ourLog.info("Got {} concepts, cloning map", code2concept.size());
final HashMap<String, TermConcept> rootConcepts = new HashMap<>(code2concept);
handler = new SctHandlerRelationship(codeSystemVersion, rootConcepts, code2concept);
iterateOverZipFile(theZipBytes, SCT_FILE_RELATIONSHIP, handler, '\t', null);
iterateOverZipFile(theDescriptors, SCT_FILE_RELATIONSHIP, handler, '\t', null);
theZipBytes.clear();
IOUtils.closeQuietly(theDescriptors);
ourLog.info("Looking for root codes");
for (Iterator<Entry<String, TermConcept>> iter = rootConcepts.entrySet().iterator(); iter.hasNext(); ) {
if (iter.next().getValue().getParents().isEmpty() == false) {
iter.remove();
}
}
rootConcepts
.entrySet()
.removeIf(theStringTermConceptEntry -> theStringTermConceptEntry.getValue().getParents().isEmpty() == false);
ourLog.info("Done loading SNOMED CT files - {} root codes, {} total codes", rootConcepts.size(), code2concept.size());
@ -313,13 +333,14 @@ public class TerminologyLoaderSvcImpl implements IHapiTerminologyLoaderSvc {
long count = circularCounter.getThenAdd();
float pct = ((float) count / rootConcepts.size()) * 100.0f;
ourLog.info(" * Scanning for circular refs - have scanned {} / {} codes ({}%)", count, rootConcepts.size(), pct);
dropCircularRefs(next, new ArrayList<String>(), code2concept, circularCounter);
dropCircularRefs(next, new ArrayList<>(), code2concept, circularCounter);
}
codeSystemVersion.getConcepts().addAll(rootConcepts.values());
CodeSystem cs = new org.hl7.fhir.r4.model.CodeSystem();
cs.setUrl(SCT_URL);
cs.setUrl(SCT_URI);
cs.setName("SNOMED CT");
cs.setContent(CodeSystem.CodeSystemContentMode.NOTPRESENT);
storeCodeSystem(theRequestDetails, codeSystemVersion, cs, null, null);
@ -351,33 +372,6 @@ public class TerminologyLoaderSvcImpl implements IHapiTerminologyLoaderSvc {
myTermSvc.setProcessDeferred(true);
}
private void verifyMandatoryFilesExist(List<byte[]> theZipBytes, List<String> theExpectedFilenameFragments) {
Set<String> foundFragments = new HashSet<>();
for (byte[] nextZipBytes : theZipBytes) {
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new ByteArrayInputStream(nextZipBytes)));
try {
for (ZipEntry nextEntry; (nextEntry = zis.getNextEntry()) != null; ) {
for (String next : theExpectedFilenameFragments) {
if (nextEntry.getName().contains(next)) {
foundFragments.add(next);
}
}
}
} catch (IOException e) {
throw new InternalErrorException(e);
} finally {
IOUtils.closeQuietly(zis);
}
}
for (String next : theExpectedFilenameFragments) {
if (!foundFragments.contains(next)) {
throw new InvalidRequestException("Invalid input zip file, expected zip to contain the following name fragments: " + theExpectedFilenameFragments + " but found: " + foundFragments);
}
}
}
public static String firstNonBlank(String... theStrings) {
String retVal = "";
@ -400,5 +394,96 @@ public class TerminologyLoaderSvcImpl implements IHapiTerminologyLoaderSvc {
return concept;
}
static class LoadedFileDescriptors implements Closeable {
private List<File> myTemporaryFiles = new ArrayList<>();
private List<IHapiTerminologyLoaderSvc.FileDescriptor> myUncompressedFileDescriptors = new ArrayList<>();
LoadedFileDescriptors(List<IHapiTerminologyLoaderSvc.FileDescriptor> theFileDescriptors) {
try {
for (FileDescriptor next : theFileDescriptors) {
File nextTemporaryFile = File.createTempFile("hapifhir", ".tmp");
nextTemporaryFile.deleteOnExit();
if (next.getFilename().toLowerCase().endsWith(".zip")) {
ourLog.info("Uncompressing {} into temporary files", next.getFilename());
try (InputStream inputStream = next.getInputStream()) {
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(inputStream));
for (ZipEntry nextEntry; (nextEntry = zis.getNextEntry()) != null; ) {
BOMInputStream fis = new BOMInputStream(zis);
FileOutputStream fos = new FileOutputStream(nextTemporaryFile);
IOUtils.copy(fis, fos);
String nextEntryFileName = nextEntry.getName();
myUncompressedFileDescriptors.add(new FileDescriptor() {
@Override
public String getFilename() {
return nextEntryFileName;
}
@Override
public InputStream getInputStream() {
try {
return new FileInputStream(nextTemporaryFile);
} catch (FileNotFoundException e) {
throw new InternalErrorException(e);
}
}
});
myTemporaryFiles.add(nextTemporaryFile);
}
}
} else {
myUncompressedFileDescriptors.add(next);
}
}
} catch (Exception e) {
close();
throw new InternalErrorException(e);
}
}
@Override
public void close() {
for (File next : myTemporaryFiles) {
FileUtils.deleteQuietly(next);
}
}
List<IHapiTerminologyLoaderSvc.FileDescriptor> getUncompressedFileDescriptors() {
return myUncompressedFileDescriptors;
}
private List<String> notFound(List<String> theExpectedFilenameFragments) {
Set<String> foundFragments = new HashSet<>();
for (String nextExpected : theExpectedFilenameFragments) {
for (FileDescriptor next : myUncompressedFileDescriptors) {
if (next.getFilename().contains(nextExpected)) {
foundFragments.add(nextExpected);
break;
}
}
}
ArrayList<String> notFoundFileNameFragments = new ArrayList<>(theExpectedFilenameFragments);
notFoundFileNameFragments.removeAll(foundFragments);
return notFoundFileNameFragments;
}
private void verifyMandatoryFilesExist(List<String> theExpectedFilenameFragments) {
List<String> notFound = notFound(theExpectedFilenameFragments);
if (!notFound.isEmpty()) {
throw new UnprocessableEntityException("Could not find the following mandatory files in input: " + notFound);
}
}
private void verifyOptionalFilesExist(List<String> theExpectedFilenameFragments) {
List<String> notFound = notFound(theExpectedFilenameFragments);
if (!notFound.isEmpty()) {
ourLog.warn("Could not find the following optional file: " + notFound);
}
}
}
}

View File

@ -2,6 +2,7 @@ package ca.uhn.fhir.jpa.term.loinc;
import ca.uhn.fhir.jpa.entity.TermConcept;
import ca.uhn.fhir.jpa.term.IRecordHandler;
import org.hl7.fhir.r4.model.ConceptMap;
import org.hl7.fhir.r4.model.Enumerations;
import org.hl7.fhir.r4.model.ValueSet;
@ -9,17 +10,20 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.*;
abstract class BaseHandler implements IRecordHandler {
private final List<ConceptMap> myConceptMaps;
private final Map<String, ConceptMap> myIdToConceptMaps = new HashMap<>();
private final List<ValueSet> myValueSets;
private final Map<String, ValueSet> myIdToValueSet = new HashMap<>();
private final Map<String, TermConcept> myCode2Concept;
BaseHandler(Map<String, TermConcept> theCode2Concept, List<ValueSet> theValueSets) {
BaseHandler(Map<String, TermConcept> theCode2Concept, List<ValueSet> theValueSets, List<ConceptMap> theConceptMaps) {
myValueSets = theValueSets;
myCode2Concept = theCode2Concept;
myConceptMaps = theConceptMaps;
}
void addCodeAsIncludeToValueSet(ValueSet theVs, String theCodeSystemUrl, String theCode, String theDisplayName) {
@ -60,6 +64,78 @@ abstract class BaseHandler implements IRecordHandler {
}
}
void addConceptMapEntry(ConceptMapping theMapping) {
if (isBlank(theMapping.getSourceCode())) {
return;
}
if (isBlank(theMapping.getTargetCode())) {
return;
}
ConceptMap conceptMap;
if (!myIdToConceptMaps.containsKey(theMapping.getConceptMapId())) {
conceptMap = new ConceptMap();
conceptMap.setId(theMapping.getConceptMapId());
conceptMap.setUrl(theMapping.getConceptMapUri());
conceptMap.setName(theMapping.getConceptMapName());
myIdToConceptMaps.put(theMapping.getConceptMapId(), conceptMap);
myConceptMaps.add(conceptMap);
} else {
conceptMap = myIdToConceptMaps.get(theMapping.getConceptMapId());
}
if (isNotBlank(theMapping.getCopyright())) {
conceptMap.setCopyright(theMapping.getCopyright());
}
ConceptMap.SourceElementComponent source = null;
ConceptMap.ConceptMapGroupComponent group = null;
for (ConceptMap.ConceptMapGroupComponent next : conceptMap.getGroup()) {
if (next.getSource().equals(theMapping.getSourceCodeSystem())) {
if (next.getTarget().equals(theMapping.getTargetCodeSystem())) {
if (!defaultString(theMapping.getTargetCodeSystemVersion()).equals(defaultString(next.getTargetVersion()))) {
continue;
}
group = next;
break;
}
}
}
if (group == null) {
group = conceptMap.addGroup();
group.setSource(theMapping.getSourceCodeSystem());
group.setTarget(theMapping.getTargetCodeSystem());
group.setTargetVersion(defaultIfBlank(theMapping.getTargetCodeSystemVersion(), null));
}
for (ConceptMap.SourceElementComponent next : group.getElement()) {
if (next.getCode().equals(theMapping.getSourceCode())) {
source = next;
}
}
if (source == null) {
source = group.addElement();
source.setCode(theMapping.getSourceCode());
source.setDisplay(theMapping.getSourceDisplay());
}
boolean found = false;
for (ConceptMap.TargetElementComponent next : source.getTarget()) {
if (next.getCode().equals(theMapping.getTargetCode())) {
found = true;
}
}
if (!found) {
source
.addTarget()
.setCode(theMapping.getTargetCode())
.setDisplay(theMapping.getTargetDisplay())
.setEquivalence(theMapping.getEquivalence());
}
}
ValueSet getValueSet(String theValueSetId, String theValueSetUri, String theValueSetName) {
ValueSet vs;
if (!myIdToValueSet.containsKey(theValueSetId)) {
@ -77,4 +153,128 @@ abstract class BaseHandler implements IRecordHandler {
}
static class ConceptMapping {
private String myCopyright;
private String myConceptMapId;
private String myConceptMapUri;
private String myConceptMapName;
private String mySourceCodeSystem;
private String mySourceCode;
private String mySourceDisplay;
private String myTargetCodeSystem;
private String myTargetCode;
private String myTargetDisplay;
private Enumerations.ConceptMapEquivalence myEquivalence;
private String myTargetCodeSystemVersion;
String getConceptMapId() {
return myConceptMapId;
}
ConceptMapping setConceptMapId(String theConceptMapId) {
myConceptMapId = theConceptMapId;
return this;
}
String getConceptMapName() {
return myConceptMapName;
}
ConceptMapping setConceptMapName(String theConceptMapName) {
myConceptMapName = theConceptMapName;
return this;
}
String getConceptMapUri() {
return myConceptMapUri;
}
ConceptMapping setConceptMapUri(String theConceptMapUri) {
myConceptMapUri = theConceptMapUri;
return this;
}
String getCopyright() {
return myCopyright;
}
ConceptMapping setCopyright(String theCopyright) {
myCopyright = theCopyright;
return this;
}
Enumerations.ConceptMapEquivalence getEquivalence() {
return myEquivalence;
}
ConceptMapping setEquivalence(Enumerations.ConceptMapEquivalence theEquivalence) {
myEquivalence = theEquivalence;
return this;
}
String getSourceCode() {
return mySourceCode;
}
ConceptMapping setSourceCode(String theSourceCode) {
mySourceCode = theSourceCode;
return this;
}
String getSourceCodeSystem() {
return mySourceCodeSystem;
}
ConceptMapping setSourceCodeSystem(String theSourceCodeSystem) {
mySourceCodeSystem = theSourceCodeSystem;
return this;
}
String getSourceDisplay() {
return mySourceDisplay;
}
ConceptMapping setSourceDisplay(String theSourceDisplay) {
mySourceDisplay = theSourceDisplay;
return this;
}
String getTargetCode() {
return myTargetCode;
}
ConceptMapping setTargetCode(String theTargetCode) {
myTargetCode = theTargetCode;
return this;
}
String getTargetCodeSystem() {
return myTargetCodeSystem;
}
ConceptMapping setTargetCodeSystem(String theTargetCodeSystem) {
myTargetCodeSystem = theTargetCodeSystem;
return this;
}
String getTargetCodeSystemVersion() {
return myTargetCodeSystemVersion;
}
ConceptMapping setTargetCodeSystemVersion(String theTargetCodeSystemVersion) {
myTargetCodeSystemVersion = theTargetCodeSystemVersion;
return this;
}
String getTargetDisplay() {
return myTargetDisplay;
}
ConceptMapping setTargetDisplay(String theTargetDisplay) {
myTargetDisplay = theTargetDisplay;
return this;
}
}
}

View File

@ -4,6 +4,7 @@ import ca.uhn.fhir.jpa.entity.TermConcept;
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
import ca.uhn.fhir.jpa.term.IRecordHandler;
import org.apache.commons.csv.CSVRecord;
import org.hl7.fhir.r4.model.ConceptMap;
import org.hl7.fhir.r4.model.ValueSet;
import java.util.List;
@ -17,8 +18,8 @@ public class BaseLoincTop2000LabResultsHandler extends BaseHandler implements IR
private String myValueSetUri;
private String myValueSetName;
public BaseLoincTop2000LabResultsHandler(Map<String, TermConcept> theCode2concept, List<ValueSet> theValueSets, String theValueSetId, String theValueSetUri, String theValueSetName) {
super(theCode2concept, theValueSets);
public BaseLoincTop2000LabResultsHandler(Map<String, TermConcept> theCode2concept, List<ValueSet> theValueSets, String theValueSetId, String theValueSetUri, String theValueSetName, List<ConceptMap> theConceptMaps) {
super(theCode2concept, theValueSets, theConceptMaps);
myValueSetId = theValueSetId;
myValueSetUri = theValueSetUri;
myValueSetName = theValueSetName;
@ -30,7 +31,7 @@ public class BaseLoincTop2000LabResultsHandler extends BaseHandler implements IR
String displayName = trim(theRecord.get("Long Common Name"));
ValueSet valueSet = getValueSet(myValueSetId, myValueSetUri, myValueSetName);
addCodeAsIncludeToValueSet(valueSet, IHapiTerminologyLoaderSvc.LOINC_URL, loincNumber, displayName);
addCodeAsIncludeToValueSet(valueSet, IHapiTerminologyLoaderSvc.LOINC_URI, loincNumber, displayName);
}
}

View File

@ -73,7 +73,7 @@ public class LoincAnswerListHandler implements IRecordHandler {
vs = new ValueSet();
vs.setUrl("urn:oid:" + answerListOid);
vs.addIdentifier()
.setSystem(IHapiTerminologyLoaderSvc.LOINC_URL)
.setSystem(IHapiTerminologyLoaderSvc.LOINC_URI)
.setValue(answerListId);
vs.setId(answerListId);
vs.setName(answerListName);
@ -86,7 +86,7 @@ public class LoincAnswerListHandler implements IRecordHandler {
vs
.getCompose()
.getIncludeFirstRep()
.setSystem(IHapiTerminologyLoaderSvc.LOINC_URL)
.setSystem(IHapiTerminologyLoaderSvc.LOINC_URI)
.addConcept()
.setCode(answerString)
.setDisplay(displayText);

View File

@ -6,7 +6,7 @@ import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
import ca.uhn.fhir.jpa.term.IRecordHandler;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import org.apache.commons.csv.CSVRecord;
import org.hl7.fhir.r4.model.Enumerations;
import org.hl7.fhir.r4.model.ConceptMap;
import org.hl7.fhir.r4.model.ValueSet;
import java.util.*;
@ -22,8 +22,8 @@ public class LoincDocumentOntologyHandler extends BaseHandler implements IRecord
private final TermCodeSystemVersion myCodeSystemVersion;
private final Set<String> myPropertyNames;
public LoincDocumentOntologyHandler(TermCodeSystemVersion theCodeSystemVersion, Map<String, TermConcept> theCode2concept, Set<String> thePropertyNames, List<ValueSet> theValueSets) {
super(theCode2concept, theValueSets);
public LoincDocumentOntologyHandler(TermCodeSystemVersion theCodeSystemVersion, Map<String, TermConcept> theCode2concept, Set<String> thePropertyNames, List<ValueSet> theValueSets, List<ConceptMap> theConceptMaps) {
super(theCode2concept, theValueSets, theConceptMaps);
myCodeSystemVersion = theCodeSystemVersion;
myCode2Concept = theCode2concept;
myPropertyNames = thePropertyNames;
@ -40,7 +40,7 @@ public class LoincDocumentOntologyHandler extends BaseHandler implements IRecord
// RSNA Codes VS
ValueSet vs = getValueSet(DOCUMENT_ONTOLOGY_CODES_VS_ID, DOCUMENT_ONTOLOGY_CODES_VS_URI, DOCUMENT_ONTOLOGY_CODES_VS_NAME);
addCodeAsIncludeToValueSet(vs, IHapiTerminologyLoaderSvc.LOINC_URL, loincNumber, null);
addCodeAsIncludeToValueSet(vs, IHapiTerminologyLoaderSvc.LOINC_URI, loincNumber, null);
// Part Properties
String loincCodePropName;
@ -66,7 +66,7 @@ public class LoincDocumentOntologyHandler extends BaseHandler implements IRecord
TermConcept code = myCode2Concept.get(loincNumber);
if (code != null) {
code.addPropertyCoding(loincCodePropName, IHapiTerminologyLoaderSvc.LOINC_URL, partNumber, partName);
code.addPropertyCoding(loincCodePropName, IHapiTerminologyLoaderSvc.LOINC_URI, partNumber, partName);
}
}

View File

@ -0,0 +1,56 @@
package ca.uhn.fhir.jpa.term.loinc;
import ca.uhn.fhir.jpa.entity.TermConcept;
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
import ca.uhn.fhir.jpa.term.IRecordHandler;
import org.apache.commons.csv.CSVRecord;
import org.hl7.fhir.r4.model.ConceptMap;
import org.hl7.fhir.r4.model.Enumerations;
import org.hl7.fhir.r4.model.ValueSet;
import java.util.List;
import java.util.Map;
import static org.apache.commons.lang3.StringUtils.trim;
public class LoincIeeeMedicalDeviceCodeHandler extends BaseHandler implements IRecordHandler {
public static final String LOINC_IEEE_CM_ID = "LOINC-IEEE-MEDICAL-DEVICE-CM";
public static final String LOINC_IEEE_CM_URI = "http://loinc.org/fhir/loinc-ieee-device-code-mappings";
public static final String LOINC_IEEE_CM_NAME = "LOINC/IEEE Device Code Mappings";
/**
* Constructor
*/
public LoincIeeeMedicalDeviceCodeHandler(Map<String, TermConcept> theCode2concept, List<ValueSet> theValueSets, List<ConceptMap> theConceptMaps) {
super(theCode2concept, theValueSets, theConceptMaps);
}
@Override
public void accept(CSVRecord theRecord) {
String loincNumber = trim(theRecord.get("LOINC_NUM"));
String longCommonName = trim(theRecord.get("LOINC_LONG_COMMON_NAME"));
String ieeeCode = trim(theRecord.get("IEEE_CF_CODE10"));
String ieeeDisplayName = trim(theRecord.get("IEEE_REFID"));
// LOINC Part -> IEEE 11073:10101 Mappings
String sourceCodeSystemUri = IHapiTerminologyLoaderSvc.LOINC_URI;
String targetCodeSystemUri = IHapiTerminologyLoaderSvc.IEEE_11073_10101_URI;
addConceptMapEntry(
new ConceptMapping()
.setConceptMapId(LOINC_IEEE_CM_ID)
.setConceptMapUri(LOINC_IEEE_CM_URI)
.setConceptMapName(LOINC_IEEE_CM_NAME)
.setSourceCodeSystem(sourceCodeSystemUri)
.setSourceCode(loincNumber)
.setSourceDisplay(longCommonName)
.setTargetCodeSystem(targetCodeSystemUri)
.setTargetCode(ieeeCode)
.setTargetDisplay(ieeeDisplayName)
.setEquivalence(Enumerations.ConceptMapEquivalence.EQUAL));
}
}

View File

@ -0,0 +1,35 @@
package ca.uhn.fhir.jpa.term.loinc;
import ca.uhn.fhir.jpa.entity.TermConcept;
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
import ca.uhn.fhir.jpa.term.IRecordHandler;
import org.apache.commons.csv.CSVRecord;
import org.hl7.fhir.r4.model.ConceptMap;
import org.hl7.fhir.r4.model.ValueSet;
import java.util.List;
import java.util.Map;
import static org.apache.commons.lang3.StringUtils.trim;
public class LoincImagingDocumentCodeHandler extends BaseHandler implements IRecordHandler {
public static final String VS_ID = "loinc-imaging-document-codes";
public static final String VS_URI = "http://loinc.org/fhir/loinc-imaging-document-codes";
public static final String VS_NAME = "LOINC Imaging Document Codes";
public LoincImagingDocumentCodeHandler(Map<String, TermConcept> theCode2concept, List<ValueSet> theValueSets, List<ConceptMap> theConceptMaps) {
super(theCode2concept, theValueSets, theConceptMaps);
}
@Override
public void accept(CSVRecord theRecord) {
String loincNumber = trim(theRecord.get("LOINC_NUM"));
String displayName = trim(theRecord.get("LONG_COMMON_NAME"));
ValueSet valueSet = getValueSet(VS_ID, VS_URI, VS_NAME);
addCodeAsIncludeToValueSet(valueSet, IHapiTerminologyLoaderSvc.LOINC_URI, loincNumber, displayName);
}
}

View File

@ -6,27 +6,26 @@ import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
import ca.uhn.fhir.jpa.term.IRecordHandler;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import org.apache.commons.csv.CSVRecord;
import org.hl7.fhir.r4.model.CanonicalType;
import org.hl7.fhir.r4.model.ConceptMap;
import org.hl7.fhir.r4.model.Enumerations;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.hl7.fhir.r4.model.ValueSet;
import java.util.List;
import java.util.Map;
import static org.apache.commons.lang3.StringUtils.defaultIfBlank;
import static org.apache.commons.lang3.StringUtils.trim;
public class LoincPartRelatedCodeMappingHandler implements IRecordHandler {
public class LoincPartRelatedCodeMappingHandler extends BaseHandler implements IRecordHandler {
public static final String LOINC_TO_SNOMED_CM_ID = "LOINC-TO-SNOMED-CM";
private static final Logger ourLog = LoggerFactory.getLogger(LoincPartRelatedCodeMappingHandler.class);
public static final String LOINC_PART_MAP_ID = "LOINC-PART-MAP";
public static final String LOINC_PART_MAP_URI = "http://loinc.org/fhir/loinc-part-map";
public static final String LOINC_PART_MAP_NAME = "LOINC Part Map";
private final Map<String, TermConcept> myCode2Concept;
private final TermCodeSystemVersion myCodeSystemVersion;
private final List<ConceptMap> myConceptMaps;
public LoincPartRelatedCodeMappingHandler(TermCodeSystemVersion theCodeSystemVersion, Map<String, TermConcept> theCode2concept, List<ConceptMap> theConceptMaps) {
public LoincPartRelatedCodeMappingHandler(TermCodeSystemVersion theCodeSystemVersion, Map<String, TermConcept> theCode2concept, List<ValueSet> theValueSets, List<ConceptMap> theConceptMaps) {
super(theCode2concept, theValueSets, theConceptMaps);
myCodeSystemVersion = theCodeSystemVersion;
myCode2Concept = theCode2concept;
myConceptMaps = theConceptMaps;
@ -48,83 +47,37 @@ public class LoincPartRelatedCodeMappingHandler implements IRecordHandler {
String extCodeSystemVersion = trim(theRecord.get("ExtCodeSystemVersion"));
String extCodeSystemCopyrightNotice = trim(theRecord.get("ExtCodeSystemCopyrightNotice"));
ConceptMap conceptMap;
if (extCodeSystem.equals(IHapiTerminologyLoaderSvc.SCT_URL)) {
conceptMap = findOrAddCodeSystem(LOINC_TO_SNOMED_CM_ID, "http://loinc.org/loinc-to-snomed", extCodeSystem, extCodeSystemCopyrightNotice);
} else {
throw new InternalErrorException("Unknown external code system ID: " + extCodeSystem);
}
ConceptMap.ConceptMapGroupComponent group = null;
for (ConceptMap.ConceptMapGroupComponent next : conceptMap.getGroup()) {
if (next.getTarget().equals(extCodeSystem)) {
if (defaultIfBlank(next.getTargetVersion(), "").equals(defaultIfBlank(extCodeSystemVersion, ""))) {
group = next;
break;
}
}
}
if (group == null) {
group = conceptMap.addGroup();
group.setSource(IHapiTerminologyLoaderSvc.LOINC_URL);
group.setTarget(extCodeSystem);
group.setTargetVersion(defaultIfBlank(extCodeSystemVersion, null));
}
ConceptMap.SourceElementComponent element = null;
for (ConceptMap.SourceElementComponent next : group.getElement()) {
if (next.getCode().equals(partNumber)) {
element = next;
break;
}
}
if (element == null) {
element = group
.addElement()
.setCode(partNumber)
.setDisplay(partName);
}
ConceptMap.TargetElementComponent target = element
.addTarget()
.setCode(extCodeId)
.setDisplay(extCodeDisplayName);
Enumerations.ConceptMapEquivalence equivalence;
switch (mapType) {
case "Exact":
// 'equal' is more exact than 'equivalent' in the equivalence codes
target.setEquivalence(Enumerations.ConceptMapEquivalence.EQUAL);
equivalence = Enumerations.ConceptMapEquivalence.EQUAL;
break;
case "LOINC broader":
target.setEquivalence(Enumerations.ConceptMapEquivalence.NARROWER);
equivalence = Enumerations.ConceptMapEquivalence.NARROWER;
break;
case "LOINC narrower":
target.setEquivalence(Enumerations.ConceptMapEquivalence.WIDER);
equivalence = Enumerations.ConceptMapEquivalence.WIDER;
break;
default:
throw new InternalErrorException("Unknown MapType: " + mapType);
}
addConceptMapEntry(
new ConceptMapping()
.setConceptMapId(LOINC_PART_MAP_ID)
.setConceptMapUri(LOINC_PART_MAP_URI)
.setConceptMapName(LOINC_PART_MAP_NAME)
.setSourceCodeSystem(IHapiTerminologyLoaderSvc.LOINC_URI)
.setSourceCode(partNumber)
.setSourceDisplay(partName)
.setTargetCodeSystem(extCodeSystem)
.setTargetCode(extCodeId)
.setTargetDisplay(extCodeDisplayName)
.setTargetCodeSystemVersion(extCodeSystemVersion)
.setEquivalence(equivalence)
.setCopyright(extCodeSystemCopyrightNotice));
}
private ConceptMap findOrAddCodeSystem(String theId, String theUri, String theTargetCodeSystem, String theTargetCopyright) {
for (ConceptMap next : myConceptMaps) {
if (next.getId().equals(theId)) {
return next;
}
}
ConceptMap cm = new ConceptMap();
cm.setId(theId);
cm.setUrl(theUri);
cm.setSource(new CanonicalType(IHapiTerminologyLoaderSvc.LOINC_URL));
cm.setTarget(new CanonicalType(theTargetCodeSystem));
cm.setCopyright(theTargetCopyright);
myConceptMaps.add(cm);
return cm;
}
}

View File

@ -6,7 +6,6 @@ import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
import ca.uhn.fhir.jpa.term.IRecordHandler;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import org.apache.commons.csv.CSVRecord;
import org.hl7.fhir.r4.model.CanonicalType;
import org.hl7.fhir.r4.model.ConceptMap;
import org.hl7.fhir.r4.model.Enumerations;
import org.hl7.fhir.r4.model.ValueSet;
@ -16,7 +15,7 @@ import java.util.*;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import static org.apache.commons.lang3.StringUtils.trim;
public class LoincRsnaPlaybookHandler implements IRecordHandler {
public class LoincRsnaPlaybookHandler extends BaseHandler implements IRecordHandler {
public static final String RSNA_CODES_VS_ID = "RSNA-LOINC-CODES-VS";
public static final String RSNA_CODES_VS_URI = "http://loinc.org/rsna-codes";
@ -34,19 +33,17 @@ public class LoincRsnaPlaybookHandler implements IRecordHandler {
private final Set<String> myPropertyNames;
private final List<ValueSet> myValueSets;
private final Map<String, ValueSet> myIdToValueSet = new HashMap<>();
private final List<ConceptMap> myConceptMaps;
private final Set<String> myCodesInRsnaPlaybookValueSet = new HashSet<>();
private final Map<String, ConceptMap> myIdToConceptMaps = new HashMap<>();
/**
* Constructor
*/
public LoincRsnaPlaybookHandler(TermCodeSystemVersion theCodeSystemVersion, Map<String, TermConcept> theCode2concept, Set<String> thePropertyNames, List<ValueSet> theValueSets, List<ConceptMap> theConceptMaps) {
super(theCode2concept, theValueSets, theConceptMaps);
myCodeSystemVersion = theCodeSystemVersion;
myCode2Concept = theCode2concept;
myPropertyNames = thePropertyNames;
myValueSets = theValueSets;
myConceptMaps = theConceptMaps;
}
@Override
@ -81,7 +78,7 @@ public class LoincRsnaPlaybookHandler implements IRecordHandler {
vs
.getCompose()
.getIncludeFirstRep()
.setSystem(IHapiTerminologyLoaderSvc.LOINC_URL)
.setSystem(IHapiTerminologyLoaderSvc.LOINC_URI)
.addConcept()
.setCode(loincNumber)
.setDisplay(longCommonName);
@ -105,61 +102,42 @@ public class LoincRsnaPlaybookHandler implements IRecordHandler {
TermConcept code = myCode2Concept.get(loincNumber);
if (code != null) {
code.addPropertyCoding(loincCodePropName, IHapiTerminologyLoaderSvc.LOINC_URL, partNumber, partName);
code.addPropertyCoding(loincCodePropName, IHapiTerminologyLoaderSvc.LOINC_URI, partNumber, partName);
}
// LOINC Part -> Radlex RID code mappings
addMapping(partNumber, partName, RID_MAPPING_CM_ID, RID_MAPPING_CM_URI, RID_MAPPING_CM_NAME, RID_CS_URI, rid, preferredName, Enumerations.ConceptMapEquivalence.EQUAL);
if (isNotBlank(rid)) {
addConceptMapEntry(
new ConceptMapping()
.setConceptMapId(RID_MAPPING_CM_ID)
.setConceptMapUri(RID_MAPPING_CM_URI)
.setConceptMapName(RID_MAPPING_CM_NAME)
.setSourceCodeSystem(IHapiTerminologyLoaderSvc.LOINC_URI)
.setSourceCode(partNumber)
.setSourceDisplay(partName)
.setTargetCodeSystem(RID_CS_URI)
.setTargetCode(rid)
.setTargetDisplay(preferredName)
.setEquivalence(Enumerations.ConceptMapEquivalence.EQUAL));
}
// LOINC Term -> Radlex RPID code mappings
addMapping(loincNumber, longCommonName, RPID_MAPPING_CM_ID, RPID_MAPPING_CM_URI, RPID_MAPPING_CM_NAME, RPID_CS_URI, rpid, longName, Enumerations.ConceptMapEquivalence.EQUAL);
}
private void addMapping(String theLoincNumber, String theLongCommonName, String theConceptMapId, String theConceptMapUri, String theConceptMapName, String theTargetCodeSystemUri, String theTargetCode, String theTargetDisplay, Enumerations.ConceptMapEquivalence theEquivalence) {
if (isNotBlank(theTargetCode)) {
ConceptMap conceptMap;
if (!myIdToConceptMaps.containsKey(theConceptMapId)) {
conceptMap = new ConceptMap();
conceptMap.setId(theConceptMapId);
conceptMap.setUrl(theConceptMapUri);
conceptMap.setName(theConceptMapName);
conceptMap.setSource(new CanonicalType(IHapiTerminologyLoaderSvc.LOINC_URL));
conceptMap.setTarget(new CanonicalType(theTargetCodeSystemUri));
myIdToConceptMaps.put(theConceptMapId, conceptMap);
myConceptMaps.add(conceptMap);
} else {
conceptMap = myIdToConceptMaps.get(theConceptMapId);
}
ConceptMap.SourceElementComponent source = null;
ConceptMap.ConceptMapGroupComponent group = conceptMap.getGroupFirstRep();
for (ConceptMap.SourceElementComponent next : group.getElement()) {
if (next.getCode().equals(theLoincNumber)) {
source = next;
}
}
if (source == null) {
source = group.addElement();
source.setCode(theLoincNumber);
source.setDisplay(theLongCommonName);
}
boolean found = false;
for (ConceptMap.TargetElementComponent next : source.getTarget()) {
if (next.getCode().equals(theTargetCode)) {
found = true;
}
}
if (!found) {
source
.addTarget()
.setCode(theTargetCode)
.setDisplay(theTargetDisplay)
.setEquivalence(theEquivalence);
}
if (isNotBlank(rpid)) {
addConceptMapEntry(
new ConceptMapping()
.setConceptMapId(RPID_MAPPING_CM_ID)
.setConceptMapUri(RPID_MAPPING_CM_URI)
.setConceptMapName(RPID_MAPPING_CM_NAME)
.setSourceCodeSystem(IHapiTerminologyLoaderSvc.LOINC_URI)
.setSourceCode(loincNumber)
.setSourceDisplay(longCommonName)
.setTargetCodeSystem(RPID_CS_URI)
.setTargetCode(rpid)
.setTargetDisplay(longName)
.setEquivalence(Enumerations.ConceptMapEquivalence.EQUAL));
}
}
}

View File

@ -1,6 +1,7 @@
package ca.uhn.fhir.jpa.term.loinc;
import ca.uhn.fhir.jpa.entity.TermConcept;
import org.hl7.fhir.r4.model.ConceptMap;
import org.hl7.fhir.r4.model.ValueSet;
import java.util.List;
@ -12,8 +13,8 @@ public class LoincTop2000LabResultsSiHandler extends BaseLoincTop2000LabResultsH
public static final String TOP_2000_SI_VS_URI = "http://loinc.org/top-2000-lab-results-si";
public static final String TOP_2000_SI_VS_NAME = "Top 2000 Lab Results SI";
public LoincTop2000LabResultsSiHandler(Map<String, TermConcept> theCode2concept, List<ValueSet> theValueSets) {
super(theCode2concept, theValueSets, TOP_2000_SI_VS_ID, TOP_2000_SI_VS_URI, TOP_2000_SI_VS_NAME);
public LoincTop2000LabResultsSiHandler(Map<String, TermConcept> theCode2concept, List<ValueSet> theValueSets, List<ConceptMap> theConceptMaps) {
super(theCode2concept, theValueSets, TOP_2000_SI_VS_ID, TOP_2000_SI_VS_URI, TOP_2000_SI_VS_NAME, theConceptMaps);
}

View File

@ -1,6 +1,7 @@
package ca.uhn.fhir.jpa.term.loinc;
import ca.uhn.fhir.jpa.entity.TermConcept;
import org.hl7.fhir.r4.model.ConceptMap;
import org.hl7.fhir.r4.model.ValueSet;
import java.util.List;
@ -12,8 +13,8 @@ public class LoincTop2000LabResultsUsHandler extends BaseLoincTop2000LabResultsH
public static final String TOP_2000_US_VS_URI = "http://loinc.org/top-2000-lab-results-us";
public static final String TOP_2000_US_VS_NAME = "Top 2000 Lab Results US";
public LoincTop2000LabResultsUsHandler(Map<String, TermConcept> theCode2concept, List<ValueSet> theValueSets) {
super(theCode2concept, theValueSets, TOP_2000_US_VS_ID, TOP_2000_US_VS_URI, TOP_2000_US_VS_NAME);
public LoincTop2000LabResultsUsHandler(Map<String, TermConcept> theCode2concept, List<ValueSet> theValueSets, List<ConceptMap> theConceptMaps) {
super(theCode2concept, theValueSets, TOP_2000_US_VS_ID, TOP_2000_US_VS_URI, TOP_2000_US_VS_NAME, theConceptMaps);
}

View File

@ -0,0 +1,35 @@
package ca.uhn.fhir.jpa.term.loinc;
import ca.uhn.fhir.jpa.entity.TermConcept;
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
import ca.uhn.fhir.jpa.term.IRecordHandler;
import org.apache.commons.csv.CSVRecord;
import org.hl7.fhir.r4.model.ConceptMap;
import org.hl7.fhir.r4.model.ValueSet;
import java.util.*;
import static org.apache.commons.lang3.StringUtils.trim;
public class LoincUniversalOrderSetHandler extends BaseHandler implements IRecordHandler {
public static final String VS_ID = "loinc-universal-order-set-vs";
public static final String VS_URI = "http://loinc.org/fhir/loinc-universal-order-set";
public static final String VS_NAME = "LOINC Universal Order Set";
public LoincUniversalOrderSetHandler(Map<String, TermConcept> theCode2concept, List<ValueSet> theValueSets, List<ConceptMap> theConceptMaps) {
super(theCode2concept, theValueSets, theConceptMaps);
}
@Override
public void accept(CSVRecord theRecord) {
String loincNumber = trim(theRecord.get("LOINC_NUM"));
String displayName = trim(theRecord.get("LONG_COMMON_NAME"));
String orderObs = trim(theRecord.get("ORDER_OBS"));
ValueSet valueSet = getValueSet(VS_ID, VS_URI, VS_NAME);
addCodeAsIncludeToValueSet(valueSet, IHapiTerminologyLoaderSvc.LOINC_URI, loincNumber, displayName);
}
}

View File

@ -96,7 +96,7 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
TermConcept childCA = new TermConcept(cs, "childCA").setDisplay("Child CA");
parentC.addChild(childCA, RelationshipTypeEnum.ISA);
myTermSvc.storeNewCodeSystemVersion(table.getId(), URL_MY_CODE_SYSTEM, cs);
myTermSvc.storeNewCodeSystemVersion(table.getId(), URL_MY_CODE_SYSTEM, "SYSTEM NAME", cs);
return codeSystem;
}
@ -127,7 +127,7 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
parentB.addChild(childI, RelationshipTypeEnum.ISA);
}
myTermSvc.storeNewCodeSystemVersion(table.getId(), URL_MY_CODE_SYSTEM, cs);
myTermSvc.storeNewCodeSystemVersion(table.getId(), URL_MY_CODE_SYSTEM, "SYSTEM NAME", cs);
return codeSystem;
}
@ -163,7 +163,7 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
TermConcept beagle = new TermConcept(cs, "beagle").setDisplay("Beagle");
dogs.addChild(beagle, RelationshipTypeEnum.ISA);
myTermSvc.storeNewCodeSystemVersion(table.getId(), URL_MY_CODE_SYSTEM, cs);
myTermSvc.storeNewCodeSystemVersion(table.getId(), URL_MY_CODE_SYSTEM,"SYSTEM NAME" , cs);
return codeSystem;
}
@ -713,7 +713,7 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
cs.setResource(table);
TermConcept parentA = new TermConcept(cs, "ParentA").setDisplay("Parent A");
cs.getConcepts().add(parentA);
myTermSvc.storeNewCodeSystemVersion(table.getId(), "http://snomed.info/sct", cs);
myTermSvc.storeNewCodeSystemVersion(table.getId(), "http://snomed.info/sct", "Snomed CT", cs);
StringType code = new StringType("ParentA");
StringType system = new StringType("http://snomed.info/sct");

View File

@ -96,7 +96,7 @@ public class FhirResourceDaoR4TerminologyTest extends BaseJpaR4Test {
TermConcept childCA = new TermConcept(cs, "childCA").setDisplay("Child CA");
parentC.addChild(childCA, RelationshipTypeEnum.ISA);
myTermSvc.storeNewCodeSystemVersion(table.getId(), URL_MY_CODE_SYSTEM, cs);
myTermSvc.storeNewCodeSystemVersion(table.getId(), URL_MY_CODE_SYSTEM,"SYSTEM NAME" , cs);
return codeSystem;
}
@ -127,7 +127,7 @@ public class FhirResourceDaoR4TerminologyTest extends BaseJpaR4Test {
parentB.addChild(childI, RelationshipTypeEnum.ISA);
}
myTermSvc.storeNewCodeSystemVersion(table.getId(), URL_MY_CODE_SYSTEM, cs);
myTermSvc.storeNewCodeSystemVersion(table.getId(), URL_MY_CODE_SYSTEM,"SYSTEM NAME" , cs);
return codeSystem;
}
@ -163,7 +163,7 @@ public class FhirResourceDaoR4TerminologyTest extends BaseJpaR4Test {
TermConcept beagle = new TermConcept(cs, "beagle").setDisplay("Beagle");
dogs.addChild(beagle, RelationshipTypeEnum.ISA);
myTermSvc.storeNewCodeSystemVersion(table.getId(), URL_MY_CODE_SYSTEM, cs);
myTermSvc.storeNewCodeSystemVersion(table.getId(), URL_MY_CODE_SYSTEM,"SYSTEM NAME" , cs);
return codeSystem;
}
@ -713,7 +713,7 @@ public class FhirResourceDaoR4TerminologyTest extends BaseJpaR4Test {
cs.setResource(table);
TermConcept parentA = new TermConcept(cs, "ParentA").setDisplay("Parent A");
cs.getConcepts().add(parentA);
myTermSvc.storeNewCodeSystemVersion(table.getId(), "http://snomed.info/sct", cs);
myTermSvc.storeNewCodeSystemVersion(table.getId(), "http://snomed.info/sct","Snomed CT" , cs);
StringType code = new StringType("ParentA");
StringType system = new StringType("http://snomed.info/sct");

View File

@ -4,6 +4,7 @@ import ca.uhn.fhir.jpa.config.WebsocketDispatcherConfig;
import ca.uhn.fhir.jpa.dao.data.ISearchDao;
import ca.uhn.fhir.jpa.dao.dstu3.BaseJpaDstu3Test;
import ca.uhn.fhir.jpa.dao.dstu3.SearchParamRegistryDstu3;
import ca.uhn.fhir.jpa.provider.TerminologyUploaderProvider;
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
import ca.uhn.fhir.jpa.search.ISearchCoordinatorSvc;
import ca.uhn.fhir.jpa.subscription.email.SubscriptionEmailInterceptor;
@ -56,7 +57,7 @@ public abstract class BaseResourceProviderDstu3Test extends BaseJpaDstu3Test {
private static Server ourServer;
protected static String ourServerBase;
protected static GenericWebApplicationContext ourWebApplicationContext;
private TerminologyUploaderProviderDstu3 myTerminologyUploaderProvider;
private TerminologyUploaderProvider myTerminologyUploaderProvider;
protected static SearchParamRegistryDstu3 ourSearchParamRegistry;
protected static DatabaseBackedPagingProvider ourPagingProvider;
protected static SubscriptionRestHookInterceptor ourRestHookSubscriptionInterceptor;
@ -92,7 +93,7 @@ public abstract class BaseResourceProviderDstu3Test extends BaseJpaDstu3Test {
ourRestServer.getFhirContext().setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator());
myTerminologyUploaderProvider = myAppCtx.getBean(TerminologyUploaderProviderDstu3.class);
myTerminologyUploaderProvider = myAppCtx.getBean(TerminologyUploaderProvider.class);
ourRestServer.setPlainProviders(mySystemProvider, myTerminologyUploaderProvider);

View File

@ -570,7 +570,7 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
TermConcept parentB = new TermConcept(cs, "ParentB").setDisplay("Parent B");
cs.getConcepts().add(parentB);
theTermSvc.storeNewCodeSystemVersion(table.getId(), URL_MY_CODE_SYSTEM, cs);
theTermSvc.storeNewCodeSystemVersion(table.getId(), URL_MY_CODE_SYSTEM, "SYSTEM NAME", cs);
return codeSystem;
}

View File

@ -47,7 +47,7 @@ public class TerminologyUploaderProviderDstu3Test extends BaseResourceProviderDs
.operation()
.onServer()
.named("upload-external-code-system")
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URL))
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI))
.andParameter("package", new Attachment().setData(packageBytes))
.execute();
//@formatter:on
@ -67,7 +67,7 @@ public class TerminologyUploaderProviderDstu3Test extends BaseResourceProviderDs
.operation()
.onServer()
.named("upload-external-code-system")
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.LOINC_URL))
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.LOINC_URI))
.andParameter("package", new Attachment().setData(packageBytes))
.execute();
//@formatter:on
@ -86,7 +86,7 @@ public class TerminologyUploaderProviderDstu3Test extends BaseResourceProviderDs
.operation()
.onServer()
.named("upload-external-code-system")
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.LOINC_URL))
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.LOINC_URI))
.andParameter("package", new Attachment().setData(packageBytes))
.execute();
//@formatter:on
@ -111,7 +111,7 @@ public class TerminologyUploaderProviderDstu3Test extends BaseResourceProviderDs
.operation()
.onServer()
.named("upload-external-code-system")
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URL))
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI))
.andParameter("localfile", new StringType(tempFile.getAbsolutePath()))
.execute();
//@formatter:on
@ -132,7 +132,7 @@ public class TerminologyUploaderProviderDstu3Test extends BaseResourceProviderDs
.operation()
.onServer()
.named("upload-external-code-system")
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URL + "FOO"))
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI + "FOO"))
.andParameter("package", new Attachment().setData(packageBytes))
.execute();
fail();
@ -169,7 +169,7 @@ public class TerminologyUploaderProviderDstu3Test extends BaseResourceProviderDs
.operation()
.onServer()
.named("upload-external-code-system")
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URL))
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI))
.execute();
fail();
} catch (InvalidRequestException e) {

View File

@ -4,6 +4,7 @@ import ca.uhn.fhir.jpa.config.WebsocketDispatcherConfig;
import ca.uhn.fhir.jpa.dao.data.ISearchDao;
import ca.uhn.fhir.jpa.dao.r4.BaseJpaR4Test;
import ca.uhn.fhir.jpa.dao.r4.SearchParamRegistryR4;
import ca.uhn.fhir.jpa.provider.TerminologyUploaderProvider;
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
import ca.uhn.fhir.jpa.search.ISearchCoordinatorSvc;
import ca.uhn.fhir.jpa.subscription.resthook.SubscriptionRestHookInterceptor;
@ -58,7 +59,7 @@ public abstract class BaseResourceProviderR4Test extends BaseJpaR4Test {
protected static ISearchCoordinatorSvc mySearchCoordinatorSvc;
private static Server ourServer;
protected static GenericWebApplicationContext ourWebApplicationContext;
private TerminologyUploaderProviderR4 myTerminologyUploaderProvider;
private TerminologyUploaderProvider myTerminologyUploaderProvider;
private Object ourGraphQLProvider;
private boolean ourRestHookSubscriptionInterceptorRequested;
@ -89,7 +90,7 @@ public abstract class BaseResourceProviderR4Test extends BaseJpaR4Test {
ourRestServer.getFhirContext().setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator());
myTerminologyUploaderProvider = myAppCtx.getBean(TerminologyUploaderProviderR4.class);
myTerminologyUploaderProvider = myAppCtx.getBean(TerminologyUploaderProvider.class);
ourGraphQLProvider = myAppCtx.getBean("myGraphQLProvider");
ourRestServer.setPlainProviders(mySystemProvider, myTerminologyUploaderProvider, ourGraphQLProvider);

View File

@ -511,7 +511,7 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test {
TermConcept parentB = new TermConcept(cs, "ParentB").setDisplay("Parent B");
cs.getConcepts().add(parentB);
theTermSvc.storeNewCodeSystemVersion(table.getId(), URL_MY_CODE_SYSTEM, cs);
theTermSvc.storeNewCodeSystemVersion(table.getId(), URL_MY_CODE_SYSTEM,"SYSTEM NAME" , cs);
return codeSystem;
}

View File

@ -47,7 +47,7 @@ public class TerminologyUploaderProviderR4Test extends BaseResourceProviderR4Tes
.operation()
.onServer()
.named("upload-external-code-system")
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URL))
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI))
.andParameter("package", new Attachment().setData(packageBytes))
.execute();
//@formatter:on
@ -67,7 +67,7 @@ public class TerminologyUploaderProviderR4Test extends BaseResourceProviderR4Tes
.operation()
.onServer()
.named("upload-external-code-system")
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.LOINC_URL))
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.LOINC_URI))
.andParameter("package", new Attachment().setData(packageBytes))
.execute();
//@formatter:on
@ -86,7 +86,7 @@ public class TerminologyUploaderProviderR4Test extends BaseResourceProviderR4Tes
.operation()
.onServer()
.named("upload-external-code-system")
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.LOINC_URL))
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.LOINC_URI))
.andParameter("package", new Attachment().setData(packageBytes))
.execute();
//@formatter:on
@ -111,7 +111,7 @@ public class TerminologyUploaderProviderR4Test extends BaseResourceProviderR4Tes
.operation()
.onServer()
.named("upload-external-code-system")
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URL))
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI))
.andParameter("localfile", new StringType(tempFile.getAbsolutePath()))
.execute();
//@formatter:on
@ -132,7 +132,7 @@ public class TerminologyUploaderProviderR4Test extends BaseResourceProviderR4Tes
.operation()
.onServer()
.named("upload-external-code-system")
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URL + "FOO"))
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI + "FOO"))
.andParameter("package", new Attachment().setData(packageBytes))
.execute();
fail();
@ -169,7 +169,7 @@ public class TerminologyUploaderProviderR4Test extends BaseResourceProviderR4Tes
.operation()
.onServer()
.named("upload-external-code-system")
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URL))
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI))
.execute();
fail();
} catch (InvalidRequestException e) {

View File

@ -16,10 +16,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.ArrayList;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.junit.Assert.assertThat;
@ -44,14 +42,15 @@ public class TerminologyLoaderSvcIntegrationDstu3Test extends BaseJpaDstu3Test {
@Test
public void testExpandWithProperty() throws Exception {
ZipCollectionBuilder files = new ZipCollectionBuilder();
TerminologyLoaderSvcLoincTest.createLoincBundle(files);
TerminologyLoaderSvcLoincTest.addLoincMandatoryFilesToZip(files);
TerminologyLoaderSvcLoincTest.addLoincOptionalFilesToZip(files);
myLoader.loadLoinc(files.getFiles(), mySrd);
ValueSet input = new ValueSet();
input
.getCompose()
.addInclude()
.setSystem(IHapiTerminologyLoaderSvc.LOINC_URL)
.setSystem(IHapiTerminologyLoaderSvc.LOINC_URI)
.addFilter()
.setProperty("SCALE_TYP")
.setOp(ValueSet.FilterOperator.EQUAL)
@ -65,10 +64,11 @@ public class TerminologyLoaderSvcIntegrationDstu3Test extends BaseJpaDstu3Test {
@Test
public void testLookupWithProperties() throws Exception {
ZipCollectionBuilder files = new ZipCollectionBuilder();
TerminologyLoaderSvcLoincTest.createLoincBundle(files);
TerminologyLoaderSvcLoincTest.addLoincMandatoryFilesToZip(files);
TerminologyLoaderSvcLoincTest.addLoincOptionalFilesToZip(files);
myLoader.loadLoinc(files.getFiles(), mySrd);
IFhirResourceDaoCodeSystem.LookupCodeResult result = myCodeSystemDao.lookupCode(new StringType("10013-1"), new StringType(IHapiTerminologyLoaderSvc.LOINC_URL), null, mySrd);
IFhirResourceDaoCodeSystem.LookupCodeResult result = myCodeSystemDao.lookupCode(new StringType("10013-1"), new StringType(IHapiTerminologyLoaderSvc.LOINC_URI), null, mySrd);
org.hl7.fhir.r4.model.Parameters parametersR4 = result.toParameters();
Parameters parameters = VersionConvertor_30_40.convertParameters(parametersR4);

View File

@ -1,9 +1,11 @@
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.term.loinc.*;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.util.TestUtil;
import org.hl7.fhir.r4.model.CodeSystem;
import org.hl7.fhir.r4.model.ConceptMap;
@ -24,6 +26,7 @@ import java.util.List;
import java.util.Map;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.empty;
import static org.junit.Assert.*;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.times;
@ -62,38 +65,43 @@ public class TerminologyLoaderSvcLoincTest {
myFiles = new ZipCollectionBuilder();
}
private Map<String, ConceptMap> extractConceptMaps() {
Map<String, ConceptMap> conceptMaps = new HashMap<>();
for (ConceptMap next : myConceptMapCaptor.getAllValues().get(0)) {
conceptMaps.put(next.getId(), next);
}
return conceptMaps;
}
private Map<String, TermConcept> extractConcepts() {
Map<String, TermConcept> concepts = new HashMap<>();
for (TermConcept next : myCsvCaptor.getValue().getConcepts()) {
concepts.put(next.getCode(), next);
}
return concepts;
}
private Map<String, ValueSet> extractValueSets() {
Map<String, ValueSet> valueSets = new HashMap<>();
for (ValueSet next : myValueSetsCaptor.getValue()) {
valueSets.put(next.getId(), next);
}
return valueSets;
}
@Test
public void testLoadLoinc() throws Exception {
createLoincBundle(myFiles);
addLoincMandatoryFilesToZip(myFiles);
addLoincOptionalFilesToZip(myFiles);
// Actually do the load
mySvc.loadLoinc(myFiles.getFiles(), details);
verify(myTermSvcDstu3, times(1)).storeNewCodeSystemVersion(mySystemCaptor.capture(), myCsvCaptor.capture(), any(RequestDetails.class), myValueSetsCaptor.capture(), myConceptMapCaptor.capture());
ValueSet input = new ValueSet();
input
.getCompose()
.addInclude()
.setSystem(IHapiTerminologyLoaderSvc.LOINC_URL)
.addFilter()
.setProperty("SCALE_TYP")
.setOp(ValueSet.FilterOperator.EQUAL)
.setValue("Ord");
Map<String, TermConcept> concepts = extractConcepts();
Map<String, ValueSet> valueSets = extractValueSets();
Map<String, ConceptMap> conceptMaps = extractConceptMaps();
TermCodeSystemVersion ver = myCsvCaptor.getValue();
Map<String, TermConcept> concepts = new HashMap<>();
for (TermConcept next : ver.getConcepts()) {
concepts.put(next.getCode(), next);
}
Map<String, ValueSet> valueSets = new HashMap<>();
for (ValueSet next : myValueSetsCaptor.getValue()) {
valueSets.put(next.getId(), next);
}
Map<String, ConceptMap> conceptMaps = new HashMap<>();
for (ConceptMap next : myConceptMapCaptor.getAllValues().get(0)) {
conceptMaps.put(next.getId(), next);
}
ConceptMap conceptMap;
TermConcept code;
ValueSet vs;
@ -127,13 +135,13 @@ public class TerminologyLoaderSvcLoincTest {
// AnswerList valueSet
vs = valueSets.get("LL1001-8");
assertEquals(IHapiTerminologyLoaderSvc.LOINC_URL, vs.getIdentifier().get(0).getSystem());
assertEquals(IHapiTerminologyLoaderSvc.LOINC_URI, vs.getIdentifier().get(0).getSystem());
assertEquals("LL1001-8", vs.getIdentifier().get(0).getValue());
assertEquals("PhenX05_14_30D freq amts", vs.getName());
assertEquals("urn:oid:1.3.6.1.4.1.12009.10.1.166", vs.getUrl());
assertEquals(1, vs.getCompose().getInclude().size());
assertEquals(7, vs.getCompose().getInclude().get(0).getConcept().size());
assertEquals(IHapiTerminologyLoaderSvc.LOINC_URL, vs.getCompose().getInclude().get(0).getSystem());
assertEquals(IHapiTerminologyLoaderSvc.LOINC_URI, vs.getCompose().getInclude().get(0).getSystem());
assertEquals("LA6270-8", vs.getCompose().getInclude().get(0).getConcept().get(0).getCode());
assertEquals("Never", vs.getCompose().getInclude().get(0).getConcept().get(0).getDisplay());
@ -143,14 +151,14 @@ public class TerminologyLoaderSvcLoincTest {
assertEquals("adjusted for maternal weight", code.getDisplay());
// Part Mappings
conceptMap = conceptMaps.get(LoincPartRelatedCodeMappingHandler.LOINC_TO_SNOMED_CM_ID);
assertEquals(IHapiTerminologyLoaderSvc.LOINC_URL, conceptMap.getSourceCanonicalType().getValueAsString());
assertEquals(IHapiTerminologyLoaderSvc.SCT_URL, conceptMap.getTargetCanonicalType().getValueAsString());
conceptMap = conceptMaps.get(LoincPartRelatedCodeMappingHandler.LOINC_PART_MAP_ID);
assertEquals(null, conceptMap.getSource());
assertEquals(null, conceptMap.getTarget());
assertEquals("This material includes SNOMED Clinical Terms® (SNOMED CT®) which is used by permission of the International Health Terminology Standards Development Organisation (IHTSDO) under license. All rights reserved. SNOMED CT® was originally created by The College of American Pathologists. “SNOMED” and “SNOMED CT” are registered trademarks of the IHTSDO.This material includes content from the US Edition to SNOMED CT, which is developed and maintained by the U.S. National Library of Medicine and is available to authorized UMLS Metathesaurus Licensees from the UTS Downloads site at https://uts.nlm.nih.gov.Use of SNOMED CT content is subject to the terms and conditions set forth in the SNOMED CT Affiliate License Agreement. It is the responsibility of those implementing this product to ensure they are appropriately licensed and for more information on the license, including how to register as an Affiliate Licensee, please refer to http://www.snomed.org/snomed-ct/get-snomed-ct or info@snomed.org<mailto:info@snomed.org>. This may incur a fee in SNOMED International non-Member countries.", conceptMap.getCopyright());
assertEquals(1, conceptMap.getGroup().size());
group = conceptMap.getGroup().get(0);
assertEquals(IHapiTerminologyLoaderSvc.LOINC_URL, group.getSource());
assertEquals(IHapiTerminologyLoaderSvc.SCT_URL, group.getTarget());
assertEquals(IHapiTerminologyLoaderSvc.LOINC_URI, group.getSource());
assertEquals(IHapiTerminologyLoaderSvc.SCT_URI, group.getTarget());
assertEquals("http://snomed.info/sct/900000000000207008/version/20170731", group.getTargetVersion());
assertEquals("LP18172-4", group.getElement().get(0).getCode());
assertEquals("Interferon.beta", group.getElement().get(0).getDisplay());
@ -163,7 +171,7 @@ public class TerminologyLoaderSvcLoincTest {
assertEquals(LoincDocumentOntologyHandler.DOCUMENT_ONTOLOGY_CODES_VS_NAME, vs.getName());
assertEquals(LoincDocumentOntologyHandler.DOCUMENT_ONTOLOGY_CODES_VS_URI, vs.getUrl());
assertEquals(1, vs.getCompose().getInclude().size());
assertEquals(IHapiTerminologyLoaderSvc.LOINC_URL, vs.getCompose().getInclude().get(0).getSystem());
assertEquals(IHapiTerminologyLoaderSvc.LOINC_URI, vs.getCompose().getInclude().get(0).getSystem());
assertEquals(3, vs.getCompose().getInclude().get(0).getConcept().size());
assertEquals("11488-4", vs.getCompose().getInclude().get(0).getConcept().get(0).getCode());
assertEquals("Consult note", vs.getCompose().getInclude().get(0).getConcept().get(0).getDisplay());
@ -171,7 +179,7 @@ public class TerminologyLoaderSvcLoincTest {
// Document ontology parts
code = concepts.get("11488-4");
assertEquals(1, code.getCodingProperties("document-kind").size());
assertEquals(IHapiTerminologyLoaderSvc.LOINC_URL, code.getCodingProperties("document-kind").get(0).getSystem());
assertEquals(IHapiTerminologyLoaderSvc.LOINC_URI, code.getCodingProperties("document-kind").get(0).getSystem());
assertEquals("LP173418-7", code.getCodingProperties("document-kind").get(0).getCode());
assertEquals("Note", code.getCodingProperties("document-kind").get(0).getDisplay());
@ -181,7 +189,7 @@ public class TerminologyLoaderSvcLoincTest {
assertEquals(LoincRsnaPlaybookHandler.RSNA_CODES_VS_URI, vs.getUrl());
assertEquals(1, vs.getCompose().getInclude().size());
assertEquals(3, vs.getCompose().getInclude().get(0).getConcept().size());
assertEquals(IHapiTerminologyLoaderSvc.LOINC_URL, vs.getCompose().getInclude().get(0).getSystem());
assertEquals(IHapiTerminologyLoaderSvc.LOINC_URI, vs.getCompose().getInclude().get(0).getSystem());
assertEquals("17787-3", vs.getCompose().getInclude().get(0).getConcept().get(0).getCode());
assertEquals("NM Thyroid gland Study report", vs.getCompose().getInclude().get(0).getConcept().get(0).getDisplay());
@ -189,21 +197,21 @@ public class TerminologyLoaderSvcLoincTest {
code = concepts.get("17787-3");
String propertyName = "rad-anatomic-location-region-imaged";
assertEquals(1, code.getCodingProperties(propertyName).size());
assertEquals(IHapiTerminologyLoaderSvc.LOINC_URL, code.getCodingProperties(propertyName).get(0).getSystem());
assertEquals(IHapiTerminologyLoaderSvc.LOINC_URI, code.getCodingProperties(propertyName).get(0).getSystem());
assertEquals("LP199995-4", code.getCodingProperties(propertyName).get(0).getCode());
assertEquals("Neck", code.getCodingProperties(propertyName).get(0).getDisplay());
// RSNA Playbook Code Parts - Imaging Focus
code = concepts.get("17787-3");
propertyName = "rad-anatomic-location-imaging-focus";
assertEquals(1, code.getCodingProperties(propertyName).size());
assertEquals(IHapiTerminologyLoaderSvc.LOINC_URL, code.getCodingProperties(propertyName).get(0).getSystem());
assertEquals(IHapiTerminologyLoaderSvc.LOINC_URI, code.getCodingProperties(propertyName).get(0).getSystem());
assertEquals("LP206648-0", code.getCodingProperties(propertyName).get(0).getCode());
assertEquals("Thyroid gland", code.getCodingProperties(propertyName).get(0).getDisplay());
// RSNA Playbook Code Parts - Modality Type
code = concepts.get("17787-3");
propertyName = "rad-modality-modality-type";
assertEquals(1, code.getCodingProperties(propertyName).size());
assertEquals(IHapiTerminologyLoaderSvc.LOINC_URL, code.getCodingProperties(propertyName).get(0).getSystem());
assertEquals(IHapiTerminologyLoaderSvc.LOINC_URI, code.getCodingProperties(propertyName).get(0).getSystem());
assertEquals("LP208891-4", code.getCodingProperties(propertyName).get(0).getCode());
assertEquals("NM", code.getCodingProperties(propertyName).get(0).getDisplay());
@ -214,8 +222,8 @@ public class TerminologyLoaderSvcLoincTest {
assertEquals(1, conceptMap.getGroup().size());
group = conceptMap.getGroupFirstRep();
// all entries have the same source and target so these should be null
assertEquals(null, group.getSource());
assertEquals(null, group.getTarget());
assertEquals(IHapiTerminologyLoaderSvc.LOINC_URI, group.getSource());
assertEquals(LoincRsnaPlaybookHandler.RID_CS_URI, group.getTarget());
assertEquals("LP199995-4", group.getElement().get(0).getCode());
assertEquals("Neck", group.getElement().get(0).getDisplay());
assertEquals(1, group.getElement().get(0).getTarget().size());
@ -230,8 +238,8 @@ public class TerminologyLoaderSvcLoincTest {
assertEquals(1, conceptMap.getGroup().size());
group = conceptMap.getGroupFirstRep();
// all entries have the same source and target so these should be null
assertEquals(null, group.getSource());
assertEquals(null, group.getTarget());
assertEquals(IHapiTerminologyLoaderSvc.LOINC_URI, group.getSource());
assertEquals(LoincRsnaPlaybookHandler.RPID_CS_URI, group.getTarget());
assertEquals("24531-6", group.getElement().get(0).getCode());
assertEquals("US Retroperitoneum", group.getElement().get(0).getDisplay());
assertEquals(1, group.getElement().get(0).getTarget().size());
@ -244,7 +252,7 @@ public class TerminologyLoaderSvcLoincTest {
assertEquals(vs.getName(), LoincTop2000LabResultsUsHandler.TOP_2000_US_VS_NAME);
assertEquals(vs.getUrl(), LoincTop2000LabResultsUsHandler.TOP_2000_US_VS_URI);
assertEquals(1, vs.getCompose().getInclude().size());
assertEquals(IHapiTerminologyLoaderSvc.LOINC_URL, vs.getCompose().getInclude().get(0).getSystem());
assertEquals(IHapiTerminologyLoaderSvc.LOINC_URI, vs.getCompose().getInclude().get(0).getSystem());
assertEquals(9, vs.getCompose().getInclude().get(0).getConcept().size());
assertEquals("2160-0", vs.getCompose().getInclude().get(0).getConcept().get(0).getCode());
assertEquals("Creatinine [Mass/volume] in Serum or Plasma", vs.getCompose().getInclude().get(0).getConcept().get(0).getDisplay());
@ -256,13 +264,109 @@ public class TerminologyLoaderSvcLoincTest {
assertEquals(vs.getName(), LoincTop2000LabResultsSiHandler.TOP_2000_SI_VS_NAME);
assertEquals(vs.getUrl(), LoincTop2000LabResultsSiHandler.TOP_2000_SI_VS_URI);
assertEquals(1, vs.getCompose().getInclude().size());
assertEquals(IHapiTerminologyLoaderSvc.LOINC_URL, vs.getCompose().getInclude().get(0).getSystem());
assertEquals(IHapiTerminologyLoaderSvc.LOINC_URI, vs.getCompose().getInclude().get(0).getSystem());
assertEquals(9, vs.getCompose().getInclude().get(0).getConcept().size());
assertEquals("14682-9", vs.getCompose().getInclude().get(0).getConcept().get(0).getCode());
assertEquals("Creatinine [Moles/volume] in Serum or Plasma", vs.getCompose().getInclude().get(0).getConcept().get(0).getDisplay());
assertEquals("718-7", vs.getCompose().getInclude().get(0).getConcept().get(1).getCode());
assertEquals("Hemoglobin [Mass/volume] in Blood", vs.getCompose().getInclude().get(0).getConcept().get(1).getDisplay());
// Universal lab order VS
vs = valueSets.get(LoincUniversalOrderSetHandler.VS_ID);
assertEquals(1, vs.getCompose().getInclude().size());
assertEquals(IHapiTerminologyLoaderSvc.LOINC_URI, vs.getCompose().getInclude().get(0).getSystem());
assertEquals(9, vs.getCompose().getInclude().get(0).getConcept().size());
assertEquals("42176-8", vs.getCompose().getInclude().get(0).getConcept().get(0).getCode());
assertEquals("1,3 beta glucan [Mass/volume] in Serum", vs.getCompose().getInclude().get(0).getConcept().get(0).getDisplay());
// IEEE Medical Device Codes
conceptMap = conceptMaps.get(LoincIeeeMedicalDeviceCodeHandler.LOINC_IEEE_CM_ID);
ourLog.info(FhirContext.forR4().newXmlParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
assertEquals(LoincIeeeMedicalDeviceCodeHandler.LOINC_IEEE_CM_NAME, conceptMap.getName());
assertEquals(LoincIeeeMedicalDeviceCodeHandler.LOINC_IEEE_CM_URI, conceptMap.getUrl());
assertEquals(1, conceptMap.getGroup().size());
assertEquals(IHapiTerminologyLoaderSvc.LOINC_URI, conceptMap.getGroup().get(0).getSource());
assertEquals(IHapiTerminologyLoaderSvc.IEEE_11073_10101_URI, conceptMap.getGroup().get(0).getTarget());
assertEquals(7, conceptMap.getGroup().get(0).getElement().size());
assertEquals("14749-6", conceptMap.getGroup().get(0).getElement().get(4).getCode());
assertEquals("Glucose [Moles/volume] in Serum or Plasma", conceptMap.getGroup().get(0).getElement().get(4).getDisplay());
assertEquals(2, conceptMap.getGroup().get(0).getElement().get(4).getTarget().size());
assertEquals("160196", conceptMap.getGroup().get(0).getElement().get(4).getTarget().get(0).getCode());
assertEquals("MDC_CONC_GLU_VENOUS_PLASMA", conceptMap.getGroup().get(0).getElement().get(4).getTarget().get(0).getDisplay());
// Imaging Document Codes
vs = valueSets.get(LoincImagingDocumentCodeHandler.VS_ID);
assertEquals(LoincImagingDocumentCodeHandler.VS_URI, vs.getUrl());
assertEquals(LoincImagingDocumentCodeHandler.VS_NAME, vs.getName());
assertEquals(1, vs.getCompose().getInclude().size());
assertEquals(IHapiTerminologyLoaderSvc.LOINC_URI, vs.getCompose().getInclude().get(0).getSystem());
assertEquals(9, vs.getCompose().getInclude().get(0).getConcept().size());
assertEquals("11525-3", vs.getCompose().getInclude().get(0).getConcept().get(0).getCode());
assertEquals("US Pelvis Fetus for pregnancy", vs.getCompose().getInclude().get(0).getConcept().get(0).getDisplay());
}
@Test
public void testLoadLoincMandatoryFilesOnly() throws IOException {
addLoincMandatoryFilesToZip(myFiles);
// Actually do the load
mySvc.loadLoinc(myFiles.getFiles(), details);
verify(myTermSvcDstu3, times(1)).storeNewCodeSystemVersion(mySystemCaptor.capture(), myCsvCaptor.capture(), any(RequestDetails.class), myValueSetsCaptor.capture(), myConceptMapCaptor.capture());
Map<String, TermConcept> concepts = extractConcepts();
Map<String, ValueSet> valueSets = extractValueSets();
Map<String, ConceptMap> conceptMaps = extractConceptMaps();
// Normal loinc code
TermConcept code = concepts.get("10013-1");
assertEquals("10013-1", code.getCode());
assertEquals("Elpot", code.getStringProperty("PROPERTY"));
assertEquals("Pt", code.getStringProperty("TIME_ASPCT"));
assertEquals("R' wave amplitude in lead I", code.getDisplay());
// No valuesets or conceptmaps get created
assertThat(valueSets.keySet(), empty());
assertThat(conceptMaps.keySet(), empty());
}
@Test
public void testLoadLoincMissingMandatoryFiles() throws IOException {
addLoincOptionalFilesToZip(myFiles);
// Actually do the load
try {
mySvc.loadLoinc(myFiles.getFiles(), details);
fail();
} catch (UnprocessableEntityException e) {
assertEquals("Could not find the following mandatory files in input: [loinc.csv, MULTI-AXIAL_HIERARCHY.CSV]", e.getMessage());
}
}
static void addLoincMandatoryFilesToZip(ZipCollectionBuilder theFiles) throws IOException {
theFiles.addFileZip("/loinc/", "loinc.csv", TerminologyLoaderSvcImpl.LOINC_FILE);
theFiles.addFileZip("/loinc/", "hierarchy.csv", TerminologyLoaderSvcImpl.LOINC_HIERARCHY_FILE);
}
static void addLoincOptionalFilesToZip(ZipCollectionBuilder theFiles) throws IOException {
theFiles.addFileZip("/loinc/", "AnswerList_Beta_1.csv", TerminologyLoaderSvcImpl.LOINC_ANSWERLIST_FILE);
theFiles.addFileZip("/loinc/", TerminologyLoaderSvcImpl.LOINC_ANSWERLIST_LINK_FILE, TerminologyLoaderSvcImpl.LOINC_ANSWERLIST_LINK_FILE);
theFiles.addFileZip("/loinc/", TerminologyLoaderSvcImpl.LOINC_PART_FILE, TerminologyLoaderSvcImpl.LOINC_PART_FILE);
theFiles.addFileZip("/loinc/", TerminologyLoaderSvcImpl.LOINC_PART_LINK_FILE, TerminologyLoaderSvcImpl.LOINC_PART_LINK_FILE);
theFiles.addFileZip("/loinc/", TerminologyLoaderSvcImpl.LOINC_PART_RELATED_CODE_MAPPING_FILE);
theFiles.addFileZip("/loinc/", TerminologyLoaderSvcImpl.LOINC_DOCUMENT_ONTOLOGY_FILE);
theFiles.addFileZip("/loinc/", TerminologyLoaderSvcImpl.LOINC_RSNA_PLAYBOOK_FILE);
theFiles.addFileZip("/loinc/", TerminologyLoaderSvcImpl.LOINC_UNIVERSAL_LAB_ORDER_VALUESET_FILE);
theFiles.addFileZip("/loinc/", TerminologyLoaderSvcImpl.LOINC_IEEE_MEDICAL_DEVICE_CODE_MAPPING_TABLE_CSV);
theFiles.addFileZip("/loinc/", TerminologyLoaderSvcImpl.LOINC_IMAGING_DOCUMENT_CODES_FILE);
/*
* Top 2000 files have versions in the filename so don't use the
* constant.. that way this is a better test
*/
theFiles.addFilePlain("/loinc/", "LOINC_1.6_Top2000CommonLabResultsSI.csv");
theFiles.addFilePlain("/loinc/", "LOINC_1.6_Top2000CommonLabResultsUS.csv");
}
@AfterClass
@ -270,22 +374,4 @@ public class TerminologyLoaderSvcLoincTest {
TestUtil.clearAllStaticFieldsForUnitTest();
}
static void createLoincBundle(ZipCollectionBuilder theFiles) throws IOException {
theFiles.addFile("/loinc/", "loinc.csv", TerminologyLoaderSvcImpl.LOINC_FILE);
theFiles.addFile("/loinc/", "hierarchy.csv", TerminologyLoaderSvcImpl.LOINC_HIERARCHY_FILE);
theFiles.addFile("/loinc/", "AnswerList_Beta_1.csv", TerminologyLoaderSvcImpl.LOINC_ANSWERLIST_FILE);
theFiles.addFile("/loinc/", TerminologyLoaderSvcImpl.LOINC_ANSWERLIST_LINK_FILE, TerminologyLoaderSvcImpl.LOINC_ANSWERLIST_LINK_FILE);
theFiles.addFile("/loinc/", TerminologyLoaderSvcImpl.LOINC_PART_FILE, TerminologyLoaderSvcImpl.LOINC_PART_FILE);
theFiles.addFile("/loinc/", TerminologyLoaderSvcImpl.LOINC_PART_LINK_FILE, TerminologyLoaderSvcImpl.LOINC_PART_LINK_FILE);
theFiles.addFile("/loinc/", TerminologyLoaderSvcImpl.LOINC_PART_RELATED_CODE_MAPPING_FILE);
theFiles.addFile("/loinc/", TerminologyLoaderSvcImpl.LOINC_DOCUMENT_ONTOLOGY_FILE);
theFiles.addFile("/loinc/", TerminologyLoaderSvcImpl.LOINC_RSNA_PLAYBOOK_FILE);
/*
* Top 2000 files have versions in the filename so don't use the
* constant.. that way this is a better test
*/
theFiles.addFile("/loinc/", "LOINC_1.6_Top2000CommonLabResultsSI.csv");
theFiles.addFile("/loinc/", "LOINC_1.6_Top2000CommonLabResultsUS.csv");
}
}

View File

@ -20,8 +20,10 @@ import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.*;
import java.util.zip.ZipOutputStream;
@ -54,19 +56,32 @@ public class TerminologyLoaderSvcSnomedCtTest {
myFiles = new ZipCollectionBuilder();
}
private List<byte[]> list(byte[]... theByteArray) {
return new ArrayList<>(Arrays.asList(theByteArray));
private ArrayList<IHapiTerminologyLoaderSvc.FileDescriptor> list(byte[]... theByteArray) {
ArrayList<IHapiTerminologyLoaderSvc.FileDescriptor> retVal = new ArrayList<>();
for (byte[] next : theByteArray) {
retVal.add(new IHapiTerminologyLoaderSvc.FileDescriptor() {
@Override
public String getFilename() {
return "aaa.zip"; }
@Override
public InputStream getInputStream() {
return new ByteArrayInputStream(next);
}
});
}
return retVal;
}
@Test
public void testLoadSnomedCt() throws Exception {
myFiles.addFile("/sct/", "sct2_Concept_Full_INT_20160131.txt");
myFiles.addFile("/sct/", "sct2_Concept_Full-en_INT_20160131.txt");
myFiles.addFile("/sct/", "sct2_Description_Full-en_INT_20160131.txt");
myFiles.addFile("/sct/", "sct2_Identifier_Full_INT_20160131.txt");
myFiles.addFile("/sct/", "sct2_Relationship_Full_INT_20160131.txt");
myFiles.addFile("/sct/", "sct2_StatedRelationship_Full_INT_20160131.txt");
myFiles.addFile("/sct/", "sct2_TextDefinition_Full-en_INT_20160131.txt");
myFiles.addFileZip("/sct/", "sct2_Concept_Full_INT_20160131.txt");
myFiles.addFileZip("/sct/", "sct2_Concept_Full-en_INT_20160131.txt");
myFiles.addFileZip("/sct/", "sct2_Description_Full-en_INT_20160131.txt");
myFiles.addFileZip("/sct/", "sct2_Identifier_Full_INT_20160131.txt");
myFiles.addFileZip("/sct/", "sct2_Relationship_Full_INT_20160131.txt");
myFiles.addFileZip("/sct/", "sct2_StatedRelationship_Full_INT_20160131.txt");
myFiles.addFileZip("/sct/", "sct2_TextDefinition_Full-en_INT_20160131.txt");
RequestDetails details = mock(RequestDetails.class);
mySvc.loadSnomedCt(myFiles.getFiles(), details);
@ -102,14 +117,14 @@ public class TerminologyLoaderSvcSnomedCtTest {
public void testLoadSnomedCtBadInput() throws Exception {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ZipOutputStream zos = new ZipOutputStream(bos);
myFiles.addFile("/sct/", "sct2_StatedRelationship_Full_INT_20160131.txt");
myFiles.addFileZip("/sct/", "sct2_StatedRelationship_Full_INT_20160131.txt");
zos.close();
ourLog.info("ZIP file has {} bytes", bos.toByteArray().length);
RequestDetails details = mock(RequestDetails.class);
try {
mySvc.loadSnomedCt(Collections.singletonList(bos.toByteArray()), details);
mySvc.loadSnomedCt(list(bos.toByteArray()), details);
fail();
} catch (InvalidRequestException e) {
assertEquals("Invalid input zip file, expected zip to contain the following name fragments: [Terminology/sct2_Description_Full-en, Terminology/sct2_Relationship_Full, Terminology/sct2_Concept_Full_] but found: []", e.getMessage());

View File

@ -61,7 +61,7 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
child.addChild(parent, RelationshipTypeEnum.ISA);
try {
myTermSvc.storeNewCodeSystemVersion(table.getId(), "http://foo", cs);
// myTermSvc.storeNewCodeSystemVersion(table.getId(), "http://foo", , cs);
fail();
} catch (InvalidRequestException e) {
assertEquals("CodeSystem contains circular reference around code parent", e.getMessage());
@ -194,7 +194,7 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
TermConcept parentB = new TermConcept(cs, "ParentB");
cs.getConcepts().add(parentB);
myTermSvc.storeNewCodeSystemVersion(table.getId(), CS_URL, cs);
myTermSvc.storeNewCodeSystemVersion(table.getId(), CS_URL,"SYSTEM NAME" , cs);
return id;
}
@ -213,7 +213,7 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
TermConcept parentA = new TermConcept(cs, "CS2");
cs.getConcepts().add(parentA);
myTermSvc.storeNewCodeSystemVersion(table.getId(), CS_URL_2, cs);
myTermSvc.storeNewCodeSystemVersion(table.getId(), CS_URL_2,"SYSTEM NAME" , cs);
return id;
}
@ -327,7 +327,7 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
TermCodeSystemVersion cs = new TermCodeSystemVersion();
cs.setResource(table);
myTermSvc.storeNewCodeSystemVersion(table.getId(), CS_URL, cs);
myTermSvc.storeNewCodeSystemVersion(table.getId(), CS_URL,"SYSTEM NAME" , cs);
// Update
cs = new TermCodeSystemVersion();
@ -336,7 +336,7 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
id = myCodeSystemDao.update(codeSystem, null, true, true, mySrd).getId().toUnqualified();
table = myResourceTableDao.findOne(id.getIdPartAsLong());
cs.setResource(table);
myTermSvc.storeNewCodeSystemVersion(table.getId(), CS_URL, cs);
myTermSvc.storeNewCodeSystemVersion(table.getId(), CS_URL,"SYSTEM NAME" , cs);
// Try to update to a different resource
codeSystem = new CodeSystem();
@ -346,7 +346,7 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
table = myResourceTableDao.findOne(id.getIdPartAsLong());
cs.setResource(table);
try {
myTermSvc.storeNewCodeSystemVersion(table.getId(), CS_URL, cs);
myTermSvc.storeNewCodeSystemVersion(table.getId(), CS_URL,"SYSTEM NAME" , cs);
fail();
} catch (UnprocessableEntityException e) {
assertThat(e.getMessage(), containsString("Can not create multiple code systems with URI \"http://example.com/my_code_system\", already have one with resource ID: CodeSystem/"));

View File

@ -5,45 +5,85 @@ import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
public class ZipCollectionBuilder {
private static final Logger ourLog = LoggerFactory.getLogger(ZipCollectionBuilder.class);
private final ArrayList<byte[]> myFiles;
private final ArrayList<IHapiTerminologyLoaderSvc.FileDescriptor> myFiles;
public ZipCollectionBuilder() {
/**
* Constructor
*/
ZipCollectionBuilder() {
myFiles = new ArrayList<>();
}
public void addFile(String theClasspathPrefix, String theClasspathFileName) throws IOException {
addFile(theClasspathPrefix, theClasspathFileName, theClasspathFileName);
/**
* Add file as a raw file
*/
public void addFilePlain(String theClasspathPrefix, String theClasspathFileName) throws IOException {
byte[] file = readFile(theClasspathPrefix, theClasspathFileName);
myFiles.add(new IHapiTerminologyLoaderSvc.FileDescriptor() {
@Override
public String getFilename() {
return theClasspathFileName;
}
@Override
public InputStream getInputStream() {
return new ByteArrayInputStream(file);
}
});
}
public void addFile(String theClasspathPrefix, String theClasspathFileName, String theOutputFilename) throws IOException {
/**
* Add file as an entry inside a ZIP file
*/
public void addFileZip(String theClasspathPrefix, String theClasspathFileName) throws IOException {
addFileZip(theClasspathPrefix, theClasspathFileName, theClasspathFileName);
}
public void addFileZip(String theClasspathPrefix, String theClasspathFileName, String theOutputFilename) throws IOException {
ByteArrayOutputStream bos;
bos = new ByteArrayOutputStream();
ZipOutputStream zos = new ZipOutputStream(bos);
ourLog.info("Adding {} to test zip", theClasspathFileName);
zos.putNextEntry(new ZipEntry("SnomedCT_Release_INT_20160131_Full/Terminology/" + theOutputFilename));
zos.write(readFile(theClasspathPrefix, theClasspathFileName));
zos.closeEntry();
zos.close();
ourLog.info("ZIP file has {} bytes", bos.toByteArray().length);
myFiles.add(new IHapiTerminologyLoaderSvc.FileDescriptor() {
@Override
public String getFilename() {
return "AAA.zip";
}
@Override
public InputStream getInputStream() {
return new ByteArrayInputStream(bos.toByteArray());
}
});
}
private byte[] readFile(String theClasspathPrefix, String theClasspathFileName) throws IOException {
String classpathName = theClasspathPrefix + theClasspathFileName;
InputStream stream = getClass().getResourceAsStream(classpathName);
Validate.notNull(stream, "Couldn't load " + classpathName);
byte[] byteArray = IOUtils.toByteArray(stream);
Validate.notNull(byteArray);
zos.write(byteArray);
zos.closeEntry();
zos.close();
ourLog.info("ZIP file has {} bytes", bos.toByteArray().length);
myFiles.add(bos.toByteArray());
return byteArray;
}
public ArrayList<byte[]> getFiles() {
public List<IHapiTerminologyLoaderSvc.FileDescriptor> getFiles() {
return myFiles;
}

View File

@ -0,0 +1,10 @@
"LOINC_NUM","LONG_COMMON_NAME"
"11525-3","US Pelvis Fetus for pregnancy"
"17787-3","NM Thyroid gland Study report"
"18744-3","Bronchoscopy study"
"18746-8","Colonoscopy study"
"18748-4","Diagnostic imaging study"
"18751-8","Endoscopy study"
"18753-4","Flexible sigmoidoscopy study"
"24531-6","US Retroperitoneum"
"24532-4","US Abdomen RUQ"
1 LOINC_NUM LONG_COMMON_NAME
2 11525-3 US Pelvis Fetus for pregnancy
3 17787-3 NM Thyroid gland Study report
4 18744-3 Bronchoscopy study
5 18746-8 Colonoscopy study
6 18748-4 Diagnostic imaging study
7 18751-8 Endoscopy study
8 18753-4 Flexible sigmoidoscopy study
9 24531-6 US Retroperitoneum
10 24532-4 US Abdomen RUQ

View File

@ -0,0 +1,10 @@
LOINC_NUM,LOINC_LONG_COMMON_NAME,IEEE_CF_CODE10,IEEE_REFID,IEEE_DESCRIPTION,IEEE_DIM,IEEE_UOM_UCUM
11556-8,Oxygen [Partial pressure] in Blood,160116,MDC_CONC_PO2_GEN,,LMT-2L-2 LMT-2L-2,kPa mm[Hg]
11557-6,Carbon dioxide [Partial pressure] in Blood,160064,MDC_CONC_PCO2_GEN,,LMT-2L-2 LMT-2L-2,kPa mm[Hg]
11558-4,pH of Blood,160004,MDC_CONC_PH_GEN,,[pH],[pH]
12961-9,Urea nitrogen [Mass/volume] in Arterial blood,160080,MDC_CONC_UREA_ART,,ML-3 NL-3,mg/dL mmol/L
14749-6,Glucose [Moles/volume] in Serum or Plasma,160196,MDC_CONC_GLU_VENOUS_PLASMA,Plasma glucose concentration taken from venous,NL-3 ,mmol/L
14749-6,Glucose [Moles/volume] in Serum or Plasma,160368,MDC_CONC_GLU_UNDETERMINED_PLASMA,Plasma glucose concentration taken from undetermined sample source,NL-3 ,mmol/L
15074-8,Glucose [Moles/volume] in Blood,160020,MDC_CONC_GLU_GEN,,NL-3,mmol/L
15074-8,Glucose [Moles/volume] in Blood,160364,MDC_CONC_GLU_UNDETERMINED_WHOLEBLOOD,Whole blood glucose concentration taken from undetermined sample source,NL-3 ,mmol/L
17861-6,Calcium [Mass/volume] in Serum or Plasma,160024,MDC_CONC_CA_GEN,,ML-3,mg/dL
1 LOINC_NUM LOINC_LONG_COMMON_NAME IEEE_CF_CODE10 IEEE_REFID IEEE_DESCRIPTION IEEE_DIM IEEE_UOM_UCUM
2 11556-8 Oxygen [Partial pressure] in Blood 160116 MDC_CONC_PO2_GEN LMT-2L-2 LMT-2L-2 kPa mm[Hg]
3 11557-6 Carbon dioxide [Partial pressure] in Blood 160064 MDC_CONC_PCO2_GEN LMT-2L-2 LMT-2L-2 kPa mm[Hg]
4 11558-4 pH of Blood 160004 MDC_CONC_PH_GEN [pH] [pH]
5 12961-9 Urea nitrogen [Mass/volume] in Arterial blood 160080 MDC_CONC_UREA_ART ML-3 NL-3 mg/dL mmol/L
6 14749-6 Glucose [Moles/volume] in Serum or Plasma 160196 MDC_CONC_GLU_VENOUS_PLASMA Plasma glucose concentration taken from venous NL-3 mmol/L
7 14749-6 Glucose [Moles/volume] in Serum or Plasma 160368 MDC_CONC_GLU_UNDETERMINED_PLASMA Plasma glucose concentration taken from undetermined sample source NL-3 mmol/L
8 15074-8 Glucose [Moles/volume] in Blood 160020 MDC_CONC_GLU_GEN NL-3 mmol/L
9 15074-8 Glucose [Moles/volume] in Blood 160364 MDC_CONC_GLU_UNDETERMINED_WHOLEBLOOD Whole blood glucose concentration taken from undetermined sample source NL-3 mmol/L
10 17861-6 Calcium [Mass/volume] in Serum or Plasma 160024 MDC_CONC_CA_GEN ML-3 mg/dL

View File

@ -0,0 +1,10 @@
"LOINC_NUM","LONG_COMMON_NAME","ORDER_OBS"
"42176-8","1,3 beta glucan [Mass/volume] in Serum","Both"
"53835-5","1,5-Anhydroglucitol [Mass/volume] in Serum or Plasma","Both"
"31019-3","10-Hydroxycarbazepine [Mass/volume] in Serum or Plasma","Both"
"6765-2","17-Hydroxypregnenolone [Mass/volume] in Serum or Plasma","Both"
"1668-3","17-Hydroxyprogesterone [Mass/volume] in Serum or Plasma","Both"
"32854-2","17-Hydroxyprogesterone [Presence] in DBS","Both"
"49054-0","25-Hydroxycalciferol [Mass/volume] in Serum or Plasma","Both"
"62292-8","25-Hydroxyvitamin D2+25-Hydroxyvitamin D3 [Mass/volume] in Serum or Plasma","Both"
"44907-4","5-Hydroxyindoleacetate panel - 24 hour Urine","Order"
1 LOINC_NUM LONG_COMMON_NAME ORDER_OBS
2 42176-8 1,3 beta glucan [Mass/volume] in Serum Both
3 53835-5 1,5-Anhydroglucitol [Mass/volume] in Serum or Plasma Both
4 31019-3 10-Hydroxycarbazepine [Mass/volume] in Serum or Plasma Both
5 6765-2 17-Hydroxypregnenolone [Mass/volume] in Serum or Plasma Both
6 1668-3 17-Hydroxyprogesterone [Mass/volume] in Serum or Plasma Both
7 32854-2 17-Hydroxyprogesterone [Presence] in DBS Both
8 49054-0 25-Hydroxycalciferol [Mass/volume] in Serum or Plasma Both
9 62292-8 25-Hydroxyvitamin D2+25-Hydroxyvitamin D3 [Mass/volume] in Serum or Plasma Both
10 44907-4 5-Hydroxyindoleacetate panel - 24 hour Urine Order

View File

@ -106,4 +106,34 @@ where res_id in (
)
drop table hfj_history_tag cascade constraints;
drop table hfj_forced_id cascade constraints;
drop table HFJ_SUBSCRIPTION_STATS cascade constraints;
drop table hfj_res_link cascade constraints;
drop table hfj_spidx_coords cascade constraints;
drop table hfj_spidx_date cascade constraints;
drop table hfj_spidx_number cascade constraints;
drop table hfj_spidx_quantity cascade constraints;
drop table hfj_spidx_string cascade constraints;
drop table hfj_spidx_token cascade constraints;
drop table hfj_spidx_uri cascade constraints;
drop table hfj_res_tag cascade constraints;
drop table hfj_search_result cascade constraints;
drop table hfj_search_include cascade constraints;
drop table hfj_search cascade constraints;
drop table hfj_res_param_present cascade constraints;
drop table hfj_idx_cmp_string_uniq cascade constraints;
drop table hfj_subscription_stats cascade constraints;
drop table trm_concept_property cascade constraints;
drop table trm_concept_pc_link cascade constraints;
drop table trm_concept cascade constraints;
drop table trm_codesystem_ver cascade constraints;
drop table trm_codesystem cascade constraints;
DROP TABLE hfj_resource CASCADE CONSTRAINTS;
DROP TABLE hfj_res_ver CASCADE CONSTRAINTS;
drop table cdr_audit_evt_target_module cascade constraints;
drop table cdr_audit_evt_target_res cascade constraints;
drop table cdr_audit_evt_target_user cascade constraints;
drop table cdr_xact_log_step cascade constraints;
drop table cdr_xact_log cascade constraints;

View File

@ -11,7 +11,7 @@ import ca.uhn.fhir.jpa.provider.dstu3.JpaSystemProviderDstu3;
import ca.uhn.fhir.jpa.provider.dstu3.TerminologyUploaderProviderDstu3;
import ca.uhn.fhir.jpa.provider.r4.JpaConformanceProviderR4;
import ca.uhn.fhir.jpa.provider.r4.JpaSystemProviderR4;
import ca.uhn.fhir.jpa.provider.r4.TerminologyUploaderProviderR4;
import ca.uhn.fhir.jpa.provider.TerminologyUploaderProvider;
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
import ca.uhn.fhir.rest.api.EncodingEnum;
@ -29,13 +29,11 @@ import org.apache.commons.lang3.StringUtils;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.cors.CorsConfiguration;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
@ -141,7 +139,7 @@ public class TestRestfulServer extends RestfulServer {
JpaConformanceProviderR4 confProvider = new JpaConformanceProviderR4(this, systemDao, myAppCtx.getBean(DaoConfig.class));
confProvider.setImplementationDescription(implDesc);
setServerConformanceProvider(confProvider);
plainProviders.add(myAppCtx.getBean(TerminologyUploaderProviderR4.class));
plainProviders.add(myAppCtx.getBean(TerminologyUploaderProvider.class));
break;
}
default:

View File

@ -207,7 +207,7 @@ public class DefaultProfileValidationSupport implements IValidationSupport {
private Map<String, StructureDefinition> provideStructureDefinitionMap(FhirContext theContext) {
Map<String, StructureDefinition> structureDefinitions = myStructureDefinitions;
if (structureDefinitions == null) {
structureDefinitions = new HashMap<String, StructureDefinition>();
structureDefinitions = new HashMap<>();
loadStructureDefinitions(theContext, structureDefinitions, "/org/hl7/fhir/dstu2016may/model/profile/profiles-resources.xml");
loadStructureDefinitions(theContext, structureDefinitions, "/org/hl7/fhir/dstu2016may/model/profile/profiles-types.xml");

View File

@ -89,7 +89,7 @@ public interface IValidationSupport
@Override
CodeValidationResult validateCode(FhirContext theContext, String theCodeSystem, String theCode, String theDisplay);
public class CodeValidationResult extends IContextValidationSupport.CodeValidationResult<ConceptDefinitionComponent, IssueSeverity> {
class CodeValidationResult extends IContextValidationSupport.CodeValidationResult<ConceptDefinitionComponent, IssueSeverity> {
public CodeValidationResult(ConceptDefinitionComponent theNext) {
super(theNext);

View File

@ -111,15 +111,15 @@ public class ValidationSupportChain implements IValidationSupport {
@Override
public CodeValidationResult validateCode(FhirContext theCtx, String theCodeSystem, String theCode, String theDisplay) {
ourLog.info("Validating code {} in chain with {} items", theCode, myChain.size());
ourLog.debug("Validating code {} in chain with {} items", theCode, myChain.size());
for (IValidationSupport next : myChain) {
if (next.isCodeSystemSupported(theCtx, theCodeSystem)) {
CodeValidationResult result = next.validateCode(theCtx, theCodeSystem, theCode, theDisplay);
ourLog.info("Chain item {} returned outcome {}", next, result.isOk());
ourLog.debug("Chain item {} returned outcome {}", next, result.isOk());
return result;
} else {
ourLog.info("Chain item {} does not support code system {}", next, theCodeSystem);
ourLog.debug("Chain item {} does not support code system {}", next, theCodeSystem);
}
}
return myChain.get(0).validateCode(theCtx, theCodeSystem, theCode, theDisplay);

View File

@ -126,15 +126,15 @@ public class ValidationSupportChain implements IValidationSupport {
@Override
public CodeValidationResult validateCode(FhirContext theCtx, String theCodeSystem, String theCode, String theDisplay) {
ourLog.info("Validating code {} in chain with {} items", theCode, myChain.size());
ourLog.debug("Validating code {} in chain with {} items", theCode, myChain.size());
for (IValidationSupport next : myChain) {
if (next.isCodeSystemSupported(theCtx, theCodeSystem)) {
CodeValidationResult result = next.validateCode(theCtx, theCodeSystem, theCode, theDisplay);
ourLog.info("Chain item {} returned outcome {}", next, result.isOk());
ourLog.debug("Chain item {} returned outcome {}", next, result.isOk());
return result;
} else {
ourLog.info("Chain item {} does not support code system {}", next, theCodeSystem);
ourLog.debug("Chain item {} does not support code system {}", next, theCodeSystem);
}
}
return myChain.get(0).validateCode(theCtx, theCodeSystem, theCode, theDisplay);