loinc updates
This commit is contained in:
parent
e31e1c029d
commit
b6232b5683
|
@ -5,9 +5,9 @@ import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||||
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
|
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
|
||||||
import ca.uhn.fhir.jpa.provider.TerminologyUploaderProvider;
|
|
||||||
import ca.uhn.fhir.jpa.provider.dstu3.JpaConformanceProviderDstu3;
|
import ca.uhn.fhir.jpa.provider.dstu3.JpaConformanceProviderDstu3;
|
||||||
import ca.uhn.fhir.jpa.provider.dstu3.JpaSystemProviderDstu3;
|
import ca.uhn.fhir.jpa.provider.dstu3.JpaSystemProviderDstu3;
|
||||||
|
import ca.uhn.fhir.jpa.provider.dstu3.TerminologyUploaderProviderDstu3;
|
||||||
import ca.uhn.fhir.jpa.rp.dstu3.ActivityDefinitionResourceProvider;
|
import ca.uhn.fhir.jpa.rp.dstu3.ActivityDefinitionResourceProvider;
|
||||||
import ca.uhn.fhir.jpa.rp.dstu3.MeasureResourceProvider;
|
import ca.uhn.fhir.jpa.rp.dstu3.MeasureResourceProvider;
|
||||||
import ca.uhn.fhir.jpa.rp.dstu3.PlanDefinitionResourceProvider;
|
import ca.uhn.fhir.jpa.rp.dstu3.PlanDefinitionResourceProvider;
|
||||||
|
@ -149,7 +149,7 @@ public class CdsServerExample extends RestfulServer {
|
||||||
* so it is a potential security vulnerability. Consider using an AuthorizationInterceptor
|
* so it is a potential security vulnerability. Consider using an AuthorizationInterceptor
|
||||||
* with this feature.
|
* with this feature.
|
||||||
*/
|
*/
|
||||||
registerProvider(myAppCtx.getBean(TerminologyUploaderProvider.class));
|
registerProvider(myAppCtx.getBean(TerminologyUploaderProviderDstu3.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
public IResourceProvider getProvider(String name) {
|
public IResourceProvider getProvider(String name) {
|
||||||
|
|
|
@ -8,9 +8,10 @@ import ca.uhn.fhir.jpa.provider.JpaConformanceProviderDstu2;
|
||||||
import ca.uhn.fhir.jpa.provider.JpaSystemProviderDstu2;
|
import ca.uhn.fhir.jpa.provider.JpaSystemProviderDstu2;
|
||||||
import ca.uhn.fhir.jpa.provider.dstu3.JpaConformanceProviderDstu3;
|
import ca.uhn.fhir.jpa.provider.dstu3.JpaConformanceProviderDstu3;
|
||||||
import ca.uhn.fhir.jpa.provider.dstu3.JpaSystemProviderDstu3;
|
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.JpaConformanceProviderR4;
|
||||||
import ca.uhn.fhir.jpa.provider.r4.JpaSystemProviderR4;
|
import ca.uhn.fhir.jpa.provider.r4.JpaSystemProviderR4;
|
||||||
import ca.uhn.fhir.jpa.provider.TerminologyUploaderProvider;
|
import ca.uhn.fhir.jpa.provider.r4.TerminologyUploaderProviderR4;
|
||||||
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
|
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.Bundle;
|
import ca.uhn.fhir.model.dstu2.resource.Bundle;
|
||||||
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
|
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
|
||||||
|
@ -78,10 +79,10 @@ public class JpaServerDemo extends RestfulServer {
|
||||||
systemProvider.add(myAppCtx.getBean("mySystemProviderDstu2", JpaSystemProviderDstu2.class));
|
systemProvider.add(myAppCtx.getBean("mySystemProviderDstu2", JpaSystemProviderDstu2.class));
|
||||||
} else if (fhirVersion == FhirVersionEnum.DSTU3) {
|
} else if (fhirVersion == FhirVersionEnum.DSTU3) {
|
||||||
systemProvider.add(myAppCtx.getBean("mySystemProviderDstu3", JpaSystemProviderDstu3.class));
|
systemProvider.add(myAppCtx.getBean("mySystemProviderDstu3", JpaSystemProviderDstu3.class));
|
||||||
systemProvider.add(myAppCtx.getBean(TerminologyUploaderProvider.class));
|
systemProvider.add(myAppCtx.getBean(TerminologyUploaderProviderDstu3.class));
|
||||||
} else if (fhirVersion == FhirVersionEnum.R4) {
|
} else if (fhirVersion == FhirVersionEnum.R4) {
|
||||||
systemProvider.add(myAppCtx.getBean("mySystemProviderR4", JpaSystemProviderR4.class));
|
systemProvider.add(myAppCtx.getBean("mySystemProviderR4", JpaSystemProviderR4.class));
|
||||||
systemProvider.add(myAppCtx.getBean(TerminologyUploaderProvider.class));
|
systemProvider.add(myAppCtx.getBean(TerminologyUploaderProviderR4.class));
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalStateException();
|
throw new IllegalStateException();
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,11 @@ import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc;
|
||||||
import ca.uhn.fhir.jpa.dao.ISearchParamRegistry;
|
import ca.uhn.fhir.jpa.dao.ISearchParamRegistry;
|
||||||
import ca.uhn.fhir.jpa.dao.dstu3.SearchParamExtractorDstu3;
|
import ca.uhn.fhir.jpa.dao.dstu3.SearchParamExtractorDstu3;
|
||||||
import ca.uhn.fhir.jpa.dao.dstu3.SearchParamRegistryDstu3;
|
import ca.uhn.fhir.jpa.dao.dstu3.SearchParamRegistryDstu3;
|
||||||
import ca.uhn.fhir.jpa.provider.TerminologyUploaderProvider;
|
import ca.uhn.fhir.jpa.provider.dstu3.TerminologyUploaderProviderDstu3;
|
||||||
import ca.uhn.fhir.jpa.term.*;
|
import ca.uhn.fhir.jpa.term.HapiTerminologySvcDstu3;
|
||||||
|
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
|
||||||
|
import ca.uhn.fhir.jpa.term.IHapiTerminologySvcDstu3;
|
||||||
|
import ca.uhn.fhir.jpa.term.TerminologyLoaderSvcImpl;
|
||||||
import ca.uhn.fhir.jpa.validation.JpaValidationSupportChainDstu3;
|
import ca.uhn.fhir.jpa.validation.JpaValidationSupportChainDstu3;
|
||||||
import ca.uhn.fhir.validation.IValidatorModule;
|
import ca.uhn.fhir.validation.IValidatorModule;
|
||||||
import org.hl7.fhir.dstu3.hapi.ctx.IValidationSupport;
|
import org.hl7.fhir.dstu3.hapi.ctx.IValidationSupport;
|
||||||
|
@ -115,8 +118,8 @@ public class BaseDstu3Config extends BaseConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean(autowire = Autowire.BY_TYPE)
|
@Bean(autowire = Autowire.BY_TYPE)
|
||||||
public TerminologyUploaderProvider terminologyUploaderProvider() {
|
public TerminologyUploaderProviderDstu3 terminologyUploaderProvider() {
|
||||||
TerminologyUploaderProvider retVal = new TerminologyUploaderProvider();
|
TerminologyUploaderProviderDstu3 retVal = new TerminologyUploaderProviderDstu3();
|
||||||
retVal.setContext(fhirContextDstu3());
|
retVal.setContext(fhirContextDstu3());
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.SearchParamExtractorR4;
|
||||||
import ca.uhn.fhir.jpa.dao.r4.SearchParamRegistryR4;
|
import ca.uhn.fhir.jpa.dao.r4.SearchParamRegistryR4;
|
||||||
import ca.uhn.fhir.jpa.graphql.JpaStorageServices;
|
import ca.uhn.fhir.jpa.graphql.JpaStorageServices;
|
||||||
import ca.uhn.fhir.jpa.provider.TerminologyUploaderProvider;
|
import ca.uhn.fhir.jpa.provider.r4.TerminologyUploaderProviderR4;
|
||||||
import ca.uhn.fhir.jpa.term.HapiTerminologySvcR4;
|
import ca.uhn.fhir.jpa.term.HapiTerminologySvcR4;
|
||||||
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
|
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
|
||||||
import ca.uhn.fhir.jpa.term.IHapiTerminologySvcR4;
|
import ca.uhn.fhir.jpa.term.IHapiTerminologySvcR4;
|
||||||
|
@ -133,8 +133,8 @@ public class BaseR4Config extends BaseConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean(autowire = Autowire.BY_TYPE)
|
@Bean(autowire = Autowire.BY_TYPE)
|
||||||
public TerminologyUploaderProvider terminologyUploaderProvider() {
|
public TerminologyUploaderProviderR4 terminologyUploaderProvider() {
|
||||||
TerminologyUploaderProvider retVal = new TerminologyUploaderProvider();
|
TerminologyUploaderProviderR4 retVal = new TerminologyUploaderProviderR4();
|
||||||
retVal.setContext(fhirContextR4());
|
retVal.setContext(fhirContextR4());
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,10 +44,12 @@ import ca.uhn.fhir.rest.api.QualifiedParamList;
|
||||||
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
||||||
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
|
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
|
||||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||||
|
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
import ca.uhn.fhir.rest.param.*;
|
import ca.uhn.fhir.rest.param.*;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.*;
|
import ca.uhn.fhir.rest.server.exceptions.*;
|
||||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
|
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
|
||||||
|
import ca.uhn.fhir.rest.server.interceptor.IServerOperationInterceptor;
|
||||||
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||||
import ca.uhn.fhir.util.*;
|
import ca.uhn.fhir.util.*;
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
@ -67,7 +69,6 @@ import org.hl7.fhir.instance.model.api.*;
|
||||||
import org.hl7.fhir.r4.model.BaseResource;
|
import org.hl7.fhir.r4.model.BaseResource;
|
||||||
import org.hl7.fhir.r4.model.Bundle.HTTPVerb;
|
import org.hl7.fhir.r4.model.Bundle.HTTPVerb;
|
||||||
import org.hl7.fhir.r4.model.CanonicalType;
|
import org.hl7.fhir.r4.model.CanonicalType;
|
||||||
import org.hl7.fhir.r4.model.IdType;
|
|
||||||
import org.hl7.fhir.r4.model.Reference;
|
import org.hl7.fhir.r4.model.Reference;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.transaction.PlatformTransactionManager;
|
import org.springframework.transaction.PlatformTransactionManager;
|
||||||
|
@ -110,6 +111,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
||||||
private static final Map<FhirVersionEnum, FhirContext> ourRetrievalContexts = new HashMap<FhirVersionEnum, FhirContext>();
|
private static final Map<FhirVersionEnum, FhirContext> ourRetrievalContexts = new HashMap<FhirVersionEnum, FhirContext>();
|
||||||
private static final String PROCESSING_SUB_REQUEST = "BaseHapiFhirDao.processingSubRequest";
|
private static final String PROCESSING_SUB_REQUEST = "BaseHapiFhirDao.processingSubRequest";
|
||||||
private static boolean ourValidationDisabledForUnitTest;
|
private static boolean ourValidationDisabledForUnitTest;
|
||||||
|
private static boolean ourDisableIncrementOnUpdateForUnitTest = false;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
Map<String, Class<? extends IQueryParameterType>> resourceMetaParams = new HashMap<String, Class<? extends IQueryParameterType>>();
|
Map<String, Class<? extends IQueryParameterType>> resourceMetaParams = new HashMap<String, Class<? extends IQueryParameterType>>();
|
||||||
|
@ -834,6 +836,22 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
||||||
return new PersistedJpaBundleProvider(search.getUuid(), this);
|
return new PersistedJpaBundleProvider(search.getUuid(), this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void incrementId(T theResource, ResourceTable theSavedEntity, IIdType theResourceId) {
|
||||||
|
String newVersion;
|
||||||
|
long newVersionLong;
|
||||||
|
if (theResourceId == null || theResourceId.getVersionIdPart() == null) {
|
||||||
|
newVersion = "1";
|
||||||
|
newVersionLong = 1;
|
||||||
|
} else {
|
||||||
|
newVersionLong = theResourceId.getVersionIdPartAsLong() + 1;
|
||||||
|
newVersion = Long.toString(newVersionLong);
|
||||||
|
}
|
||||||
|
|
||||||
|
IIdType newId = theResourceId.withVersion(newVersion);
|
||||||
|
theResource.getIdElement().setValue(newId.getValue());
|
||||||
|
theSavedEntity.setVersion(newVersionLong);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void injectDependenciesIntoBundleProvider(PersistedJpaBundleProvider theProvider) {
|
public void injectDependenciesIntoBundleProvider(PersistedJpaBundleProvider theProvider) {
|
||||||
theProvider.setContext(getContext());
|
theProvider.setContext(getContext());
|
||||||
|
@ -1816,6 +1834,55 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
||||||
return updateEntity(theResource, entity, theDeletedTimestampOrNull, true, true, theUpdateTime, false, true);
|
return updateEntity(theResource, entity, theDeletedTimestampOrNull, true, true, theUpdateTime, false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ResourceTable updateInternal(T theResource, boolean thePerformIndexing, boolean theForceUpdateVersion, RequestDetails theRequestDetails, ResourceTable theEntity, IIdType theResourceId, IBaseResource theOldResource) {
|
||||||
|
// Notify interceptors
|
||||||
|
ActionRequestDetails requestDetails = null;
|
||||||
|
if (theRequestDetails != null) {
|
||||||
|
requestDetails = new ActionRequestDetails(theRequestDetails, theResource, theResourceId.getResourceType(), theResourceId);
|
||||||
|
notifyInterceptors(RestOperationTypeEnum.UPDATE, requestDetails);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notify IServerOperationInterceptors about pre-action call
|
||||||
|
if (theRequestDetails != null) {
|
||||||
|
theRequestDetails.getRequestOperationCallback().resourcePreUpdate(theOldResource, theResource);
|
||||||
|
}
|
||||||
|
for (IServerInterceptor next : getConfig().getInterceptors()) {
|
||||||
|
if (next instanceof IServerOperationInterceptor) {
|
||||||
|
((IServerOperationInterceptor) next).resourcePreUpdate(theRequestDetails, theOldResource, theResource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform update
|
||||||
|
ResourceTable savedEntity = updateEntity(theResource, theEntity, null, thePerformIndexing, thePerformIndexing, new Date(), theForceUpdateVersion, thePerformIndexing);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we aren't indexing (meaning we're probably executing a sub-operation within a transaction),
|
||||||
|
* we'll manually increase the version. This is important because we want the updated version number
|
||||||
|
* to be reflected in the resource shared with interceptors
|
||||||
|
*/
|
||||||
|
if (!thePerformIndexing && !savedEntity.isUnchangedInCurrentOperation() && !ourDisableIncrementOnUpdateForUnitTest) {
|
||||||
|
if (theResourceId.hasVersionIdPart() == false) {
|
||||||
|
theResourceId = theResourceId.withVersion(Long.toString(savedEntity.getVersion()));
|
||||||
|
}
|
||||||
|
incrementId(theResource, savedEntity, theResourceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notify interceptors
|
||||||
|
if (!savedEntity.isUnchangedInCurrentOperation()) {
|
||||||
|
if (theRequestDetails != null) {
|
||||||
|
theRequestDetails.getRequestOperationCallback().resourceUpdated(theResource);
|
||||||
|
theRequestDetails.getRequestOperationCallback().resourceUpdated(theOldResource, theResource);
|
||||||
|
}
|
||||||
|
for (IServerInterceptor next : getConfig().getInterceptors()) {
|
||||||
|
if (next instanceof IServerOperationInterceptor) {
|
||||||
|
((IServerOperationInterceptor) next).resourceUpdated(theRequestDetails, theResource);
|
||||||
|
((IServerOperationInterceptor) next).resourceUpdated(theRequestDetails, theOldResource, theResource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return savedEntity;
|
||||||
|
}
|
||||||
|
|
||||||
private void validateChildReferences(IBase theElement, String thePath) {
|
private void validateChildReferences(IBase theElement, String thePath) {
|
||||||
if (theElement == null) {
|
if (theElement == null) {
|
||||||
return;
|
return;
|
||||||
|
@ -2133,6 +2200,11 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
||||||
return b.toString();
|
return b.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
public static void setDisableIncrementOnUpdateForUnitTest(boolean theDisableIncrementOnUpdateForUnitTest) {
|
||||||
|
ourDisableIncrementOnUpdateForUnitTest = theDisableIncrementOnUpdateForUnitTest;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Do not call this method outside of unit tests
|
* Do not call this method outside of unit tests
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -77,7 +77,6 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends BaseHapiFhirDao<T> implements IFhirResourceDao<T> {
|
public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends BaseHapiFhirDao<T> implements IFhirResourceDao<T> {
|
||||||
|
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseHapiFhirResourceDao.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseHapiFhirResourceDao.class);
|
||||||
private static boolean ourDisableIncrementOnUpdateForUnitTest = false;
|
|
||||||
@Autowired
|
@Autowired
|
||||||
protected PlatformTransactionManager myPlatformTransactionManager;
|
protected PlatformTransactionManager myPlatformTransactionManager;
|
||||||
@Autowired
|
@Autowired
|
||||||
|
@ -592,22 +591,6 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void incrementId(T theResource, ResourceTable theSavedEntity, IIdType theResourceId) {
|
|
||||||
String newVersion;
|
|
||||||
long newVersionLong;
|
|
||||||
if (theResourceId == null || theResourceId.getVersionIdPart() == null) {
|
|
||||||
newVersion = "1";
|
|
||||||
newVersionLong = 1;
|
|
||||||
} else {
|
|
||||||
newVersionLong = theResourceId.getVersionIdPartAsLong() + 1;
|
|
||||||
newVersion = Long.toString(newVersionLong);
|
|
||||||
}
|
|
||||||
|
|
||||||
IIdType newId = theResourceId.withVersion(newVersion);
|
|
||||||
theResource.getIdElement().setValue(newId.getValue());
|
|
||||||
theSavedEntity.setVersion(newVersionLong);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean isPagingProviderDatabaseBacked(RequestDetails theRequestDetails) {
|
protected boolean isPagingProviderDatabaseBacked(RequestDetails theRequestDetails) {
|
||||||
if (theRequestDetails == null || theRequestDetails.getServer() == null) {
|
if (theRequestDetails == null || theRequestDetails.getServer() == null) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -1229,54 +1212,24 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
"Invalid resource ID[" + entity.getIdDt().toUnqualifiedVersionless() + "] of type[" + entity.getResourceType() + "] - Does not match expected [" + getResourceName() + "]");
|
"Invalid resource ID[" + entity.getIdDt().toUnqualifiedVersionless() + "] of type[" + entity.getResourceType() + "] - Does not match expected [" + getResourceName() + "]");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notify interceptors
|
|
||||||
ActionRequestDetails requestDetails = null;
|
|
||||||
if (theRequestDetails != null) {
|
|
||||||
requestDetails = new ActionRequestDetails(theRequestDetails, theResource, getResourceName(), resourceId);
|
|
||||||
notifyInterceptors(RestOperationTypeEnum.UPDATE, requestDetails);
|
|
||||||
}
|
|
||||||
|
|
||||||
IBaseResource oldResource = toResource(entity, false);
|
IBaseResource oldResource = toResource(entity, false);
|
||||||
|
|
||||||
// Notify IServerOperationInterceptors about pre-action call
|
/*
|
||||||
if (theRequestDetails != null) {
|
* If we aren't indexing, that means we're doing this inside a transaction.
|
||||||
theRequestDetails.getRequestOperationCallback().resourcePreUpdate(oldResource, theResource);
|
* The transaction will do the actual storate to the database a bit later on,
|
||||||
|
* after placeholder IDs have been replaced, by calling {@link #updateInternal}
|
||||||
|
* directly. So we just bail now.
|
||||||
|
*/
|
||||||
|
if (!thePerformIndexing) {
|
||||||
|
DaoMethodOutcome outcome = toMethodOutcome(entity, theResource).setCreated(false);
|
||||||
|
outcome.setPreviousResource(oldResource);
|
||||||
|
return outcome;
|
||||||
}
|
}
|
||||||
for (IServerInterceptor next : getConfig().getInterceptors()) {
|
|
||||||
if (next instanceof IServerOperationInterceptor) {
|
|
||||||
((IServerOperationInterceptor) next).resourcePreUpdate(theRequestDetails, oldResource, theResource);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Perform update
|
|
||||||
ResourceTable savedEntity = updateEntity(theResource, entity, null, thePerformIndexing, thePerformIndexing, new Date(), theForceUpdateVersion, thePerformIndexing);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we aren't indexing (meaning we're probably executing a sub-operation within a transaction),
|
* Otherwise, we're not in a transaction
|
||||||
* we'll manually increase the version. This is important because we want the updated version number
|
|
||||||
* to be reflected in the resource shared with interceptors
|
|
||||||
*/
|
*/
|
||||||
if (!thePerformIndexing && !savedEntity.isUnchangedInCurrentOperation() && !ourDisableIncrementOnUpdateForUnitTest) {
|
ResourceTable savedEntity = updateInternal(theResource, thePerformIndexing, theForceUpdateVersion, theRequestDetails, entity, resourceId, oldResource);
|
||||||
if (resourceId.hasVersionIdPart() == false) {
|
|
||||||
resourceId = resourceId.withVersion(Long.toString(savedEntity.getVersion()));
|
|
||||||
}
|
|
||||||
incrementId(theResource, savedEntity, resourceId);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Notify interceptors
|
|
||||||
if (!savedEntity.isUnchangedInCurrentOperation()) {
|
|
||||||
if (theRequestDetails != null) {
|
|
||||||
theRequestDetails.getRequestOperationCallback().resourceUpdated(theResource);
|
|
||||||
theRequestDetails.getRequestOperationCallback().resourceUpdated(oldResource, theResource);
|
|
||||||
}
|
|
||||||
for (IServerInterceptor next : getConfig().getInterceptors()) {
|
|
||||||
if (next instanceof IServerOperationInterceptor) {
|
|
||||||
((IServerOperationInterceptor) next).resourceUpdated(theRequestDetails, theResource);
|
|
||||||
((IServerOperationInterceptor) next).resourceUpdated(theRequestDetails, oldResource, theResource);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DaoMethodOutcome outcome = toMethodOutcome(savedEntity, theResource).setCreated(false);
|
DaoMethodOutcome outcome = toMethodOutcome(savedEntity, theResource).setCreated(false);
|
||||||
|
|
||||||
if (!thePerformIndexing) {
|
if (!thePerformIndexing) {
|
||||||
|
@ -1366,9 +1319,5 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
public static void setDisableIncrementOnUpdateForUnitTest(boolean theDisableIncrementOnUpdateForUnitTest) {
|
|
||||||
ourDisableIncrementOnUpdateForUnitTest = theDisableIncrementOnUpdateForUnitTest;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,24 +22,41 @@ package ca.uhn.fhir.jpa.dao;
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.entity.ResourceTable;
|
import ca.uhn.fhir.jpa.entity.ResourceTable;
|
||||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
|
||||||
public class DaoMethodOutcome extends MethodOutcome {
|
public class DaoMethodOutcome extends MethodOutcome {
|
||||||
|
|
||||||
private ResourceTable myEntity;
|
private ResourceTable myEntity;
|
||||||
|
private IBaseResource myPreviousResource;
|
||||||
|
|
||||||
public ResourceTable getEntity() {
|
public ResourceTable getEntity() {
|
||||||
return myEntity;
|
return myEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public DaoMethodOutcome setCreated(Boolean theCreated) {
|
|
||||||
super.setCreated(theCreated);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public DaoMethodOutcome setEntity(ResourceTable theEntity) {
|
public DaoMethodOutcome setEntity(ResourceTable theEntity) {
|
||||||
myEntity = theEntity;
|
myEntity = theEntity;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For update operations, this is the body of the resource as it was before the
|
||||||
|
* update
|
||||||
|
*/
|
||||||
|
public IBaseResource getPreviousResource() {
|
||||||
|
return myPreviousResource;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For update operations, this is the body of the resource as it was before the
|
||||||
|
* update
|
||||||
|
*/
|
||||||
|
public void setPreviousResource(IBaseResource thePreviousResource) {
|
||||||
|
myPreviousResource = thePreviousResource;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DaoMethodOutcome setCreated(Boolean theCreated) {
|
||||||
|
super.setCreated(theCreated);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,24 +19,6 @@ package ca.uhn.fhir.jpa.dao;
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
import static org.apache.commons.lang3.StringUtils.*;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import javax.persistence.TypedQuery;
|
|
||||||
|
|
||||||
import ca.uhn.fhir.model.primitive.UriDt;
|
|
||||||
import org.apache.http.NameValuePair;
|
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.transaction.*;
|
|
||||||
import org.springframework.transaction.annotation.Propagation;
|
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
|
||||||
import org.springframework.transaction.support.TransactionCallback;
|
|
||||||
import org.springframework.transaction.support.TransactionTemplate;
|
|
||||||
|
|
||||||
import com.google.common.collect.ArrayListMultimap;
|
|
||||||
|
|
||||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||||
import ca.uhn.fhir.jpa.entity.ResourceTable;
|
import ca.uhn.fhir.jpa.entity.ResourceTable;
|
||||||
|
@ -51,15 +33,23 @@ import ca.uhn.fhir.model.dstu2.resource.Bundle;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.Bundle.Entry;
|
import ca.uhn.fhir.model.dstu2.resource.Bundle.Entry;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.Bundle.EntryResponse;
|
import ca.uhn.fhir.model.dstu2.resource.Bundle.EntryResponse;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.OperationOutcome;
|
import ca.uhn.fhir.model.dstu2.resource.OperationOutcome;
|
||||||
import ca.uhn.fhir.model.dstu2.valueset.*;
|
import ca.uhn.fhir.model.dstu2.valueset.BundleTypeEnum;
|
||||||
|
import ca.uhn.fhir.model.dstu2.valueset.HTTPVerbEnum;
|
||||||
|
import ca.uhn.fhir.model.dstu2.valueset.IssueSeverityEnum;
|
||||||
import ca.uhn.fhir.model.primitive.IdDt;
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
import ca.uhn.fhir.model.primitive.InstantDt;
|
import ca.uhn.fhir.model.primitive.InstantDt;
|
||||||
|
import ca.uhn.fhir.model.primitive.UriDt;
|
||||||
import ca.uhn.fhir.parser.DataFormatException;
|
import ca.uhn.fhir.parser.DataFormatException;
|
||||||
import ca.uhn.fhir.parser.IParser;
|
import ca.uhn.fhir.parser.IParser;
|
||||||
import ca.uhn.fhir.rest.api.*;
|
import ca.uhn.fhir.rest.api.Constants;
|
||||||
|
import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
||||||
|
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
||||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
import ca.uhn.fhir.rest.server.RestfulServerUtils;
|
import ca.uhn.fhir.rest.server.RestfulServerUtils;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.*;
|
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.NotModifiedException;
|
||||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
|
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
|
||||||
import ca.uhn.fhir.rest.server.method.BaseMethodBinding;
|
import ca.uhn.fhir.rest.server.method.BaseMethodBinding;
|
||||||
import ca.uhn.fhir.rest.server.method.BaseResourceReturningMethodBinding;
|
import ca.uhn.fhir.rest.server.method.BaseResourceReturningMethodBinding;
|
||||||
|
@ -67,6 +57,23 @@ import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||||
import ca.uhn.fhir.util.FhirTerser;
|
import ca.uhn.fhir.util.FhirTerser;
|
||||||
import ca.uhn.fhir.util.UrlUtil;
|
import ca.uhn.fhir.util.UrlUtil;
|
||||||
import ca.uhn.fhir.util.UrlUtil.UrlParts;
|
import ca.uhn.fhir.util.UrlUtil.UrlParts;
|
||||||
|
import com.google.common.collect.ArrayListMultimap;
|
||||||
|
import org.apache.http.NameValuePair;
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.transaction.PlatformTransactionManager;
|
||||||
|
import org.springframework.transaction.TransactionDefinition;
|
||||||
|
import org.springframework.transaction.TransactionStatus;
|
||||||
|
import org.springframework.transaction.annotation.Propagation;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.transaction.support.TransactionCallback;
|
||||||
|
import org.springframework.transaction.support.TransactionTemplate;
|
||||||
|
|
||||||
|
import javax.persistence.TypedQuery;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import static org.apache.commons.lang3.StringUtils.*;
|
||||||
|
|
||||||
public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle, MetaDt> {
|
public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle, MetaDt> {
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirSystemDaoDstu2.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirSystemDaoDstu2.class);
|
||||||
|
@ -137,121 +144,11 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle, MetaDt> {
|
||||||
}
|
}
|
||||||
|
|
||||||
long delay = System.currentTimeMillis() - start;
|
long delay = System.currentTimeMillis() - start;
|
||||||
ourLog.info("Batch completed in {}ms", new Object[] { delay });
|
ourLog.info("Batch completed in {}ms", new Object[] {delay});
|
||||||
|
|
||||||
return resp;
|
return resp;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String extractTransactionUrlOrThrowException(Entry nextEntry, HTTPVerbEnum verb) {
|
|
||||||
String url = nextEntry.getRequest().getUrl();
|
|
||||||
if (isBlank(url)) {
|
|
||||||
throw new InvalidRequestException(getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionMissingUrl", verb.name()));
|
|
||||||
}
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method is called for nested bundles (e.g. if we received a transaction with an entry that
|
|
||||||
* was a GET search, this method is called on the bundle for the search result, that will be placed in the
|
|
||||||
* outer bundle). This method applies the _summary and _content parameters to the output of
|
|
||||||
* that bundle.
|
|
||||||
*
|
|
||||||
* TODO: This isn't the most efficient way of doing this.. hopefully we can come up with something better in the future.
|
|
||||||
*/
|
|
||||||
private IBaseResource filterNestedBundle(RequestDetails theRequestDetails, IBaseResource theResource) {
|
|
||||||
IParser p = getContext().newJsonParser();
|
|
||||||
RestfulServerUtils.configureResponseParser(theRequestDetails, p);
|
|
||||||
return p.parseResource(theResource.getClass(), p.encodeResourceToString(theResource));
|
|
||||||
}
|
|
||||||
|
|
||||||
private IFhirResourceDao<?> getDaoOrThrowException(Class<? extends IResource> theClass) {
|
|
||||||
IFhirResourceDao<? extends IResource> retVal = getDao(theClass);
|
|
||||||
if (retVal == null) {
|
|
||||||
throw new InvalidRequestException("Unable to process request, this server does not know how to handle resources of type " + getContext().getResourceDefinition(theClass).getName());
|
|
||||||
}
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MetaDt metaGetOperation(RequestDetails theRequestDetails) {
|
|
||||||
// Notify interceptors
|
|
||||||
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails);
|
|
||||||
notifyInterceptors(RestOperationTypeEnum.META, requestDetails);
|
|
||||||
|
|
||||||
String sql = "SELECT d FROM TagDefinition d WHERE d.myId IN (SELECT DISTINCT t.myTagId FROM ResourceTag t)";
|
|
||||||
TypedQuery<TagDefinition> q = myEntityManager.createQuery(sql, TagDefinition.class);
|
|
||||||
List<TagDefinition> tagDefinitions = q.getResultList();
|
|
||||||
|
|
||||||
MetaDt retVal = toMetaDt(tagDefinitions);
|
|
||||||
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected MetaDt toMetaDt(Collection<TagDefinition> tagDefinitions) {
|
|
||||||
MetaDt retVal = new MetaDt();
|
|
||||||
for (TagDefinition next : tagDefinitions) {
|
|
||||||
switch (next.getTagType()) {
|
|
||||||
case PROFILE:
|
|
||||||
retVal.addProfile(next.getCode());
|
|
||||||
break;
|
|
||||||
case SECURITY_LABEL:
|
|
||||||
retVal.addSecurity().setSystem(next.getSystem()).setCode(next.getCode()).setDisplay(next.getDisplay());
|
|
||||||
break;
|
|
||||||
case TAG:
|
|
||||||
retVal.addTag().setSystem(next.getSystem()).setCode(next.getCode()).setDisplay(next.getDisplay());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private ca.uhn.fhir.jpa.dao.IFhirResourceDao<? extends IBaseResource> toDao(UrlParts theParts, String theVerb, String theUrl) {
|
|
||||||
RuntimeResourceDefinition resType;
|
|
||||||
try {
|
|
||||||
resType = getContext().getResourceDefinition(theParts.getResourceType());
|
|
||||||
} catch (DataFormatException e) {
|
|
||||||
String msg = getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionInvalidUrl", theVerb, theUrl);
|
|
||||||
throw new InvalidRequestException(msg);
|
|
||||||
}
|
|
||||||
IFhirResourceDao<? extends IBaseResource> dao = null;
|
|
||||||
if (resType != null) {
|
|
||||||
dao = getDao(resType.getImplementingClass());
|
|
||||||
}
|
|
||||||
if (dao == null) {
|
|
||||||
String msg = getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionInvalidUrl", theVerb, theUrl);
|
|
||||||
throw new InvalidRequestException(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
// if (theParts.getResourceId() == null && theParts.getParams() == null) {
|
|
||||||
// String msg = getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionInvalidUrl", theVerb, theUrl);
|
|
||||||
// throw new InvalidRequestException(msg);
|
|
||||||
// }
|
|
||||||
|
|
||||||
return dao;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Transactional(propagation = Propagation.REQUIRED)
|
|
||||||
@Override
|
|
||||||
public Bundle transaction(RequestDetails theRequestDetails, Bundle theRequest) {
|
|
||||||
if (theRequestDetails != null) {
|
|
||||||
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails, theRequest, "Bundle", null);
|
|
||||||
notifyInterceptors(RestOperationTypeEnum.TRANSACTION, requestDetails);
|
|
||||||
}
|
|
||||||
|
|
||||||
String actionName = "Transaction";
|
|
||||||
return transaction((ServletRequestDetails) theRequestDetails, theRequest, actionName);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Bundle transaction(ServletRequestDetails theRequestDetails, Bundle theRequest, String theActionName) {
|
|
||||||
super.markRequestAsProcessingSubRequest(theRequestDetails);
|
|
||||||
try {
|
|
||||||
return doTransaction(theRequestDetails, theRequest, theActionName);
|
|
||||||
} finally {
|
|
||||||
super.clearRequestAsProcessingSubRequest(theRequestDetails);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private Bundle doTransaction(ServletRequestDetails theRequestDetails, Bundle theRequest, String theActionName) {
|
private Bundle doTransaction(ServletRequestDetails theRequestDetails, Bundle theRequest, String theActionName) {
|
||||||
BundleTypeEnum transactionType = theRequest.getTypeElement().getValueAsEnum();
|
BundleTypeEnum transactionType = theRequest.getTypeElement().getValueAsEnum();
|
||||||
|
@ -299,10 +196,11 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle, MetaDt> {
|
||||||
}
|
}
|
||||||
Collections.sort(theRequest.getEntry(), new TransactionSorter());
|
Collections.sort(theRequest.getEntry(), new TransactionSorter());
|
||||||
|
|
||||||
List<IIdType> deletedResources = new ArrayList<IIdType>();
|
List<IIdType> deletedResources = new ArrayList<>();
|
||||||
List<DeleteConflict> deleteConflicts = new ArrayList<DeleteConflict>();
|
List<DeleteConflict> deleteConflicts = new ArrayList<>();
|
||||||
Map<Entry, ResourceTable> entriesToProcess = new IdentityHashMap<Entry, ResourceTable>();
|
Map<Entry, ResourceTable> entriesToProcess = new IdentityHashMap<>();
|
||||||
Set<ResourceTable> nonUpdatedEntities = new HashSet<ResourceTable>();
|
Set<ResourceTable> nonUpdatedEntities = new HashSet<ResourceTable>();
|
||||||
|
Set<ResourceTable> updatedEntities = new HashSet<>();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Loop through the request and process any entries of type
|
* Loop through the request and process any entries of type
|
||||||
|
@ -321,7 +219,7 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle, MetaDt> {
|
||||||
|
|
||||||
nextResourceId = res.getId();
|
nextResourceId = res.getId();
|
||||||
|
|
||||||
if (nextResourceId.hasIdPart() == false) {
|
if (!nextResourceId.hasIdPart()) {
|
||||||
if (isNotBlank(nextReqEntry.getFullUrl())) {
|
if (isNotBlank(nextReqEntry.getFullUrl())) {
|
||||||
nextResourceId = new IdDt(nextReqEntry.getFullUrl());
|
nextResourceId = new IdDt(nextReqEntry.getFullUrl());
|
||||||
}
|
}
|
||||||
|
@ -419,6 +317,10 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle, MetaDt> {
|
||||||
outcome = resourceDao.update(res, parts.getResourceType() + '?' + parts.getParams(), false, theRequestDetails);
|
outcome = resourceDao.update(res, parts.getResourceType() + '?' + parts.getParams(), false, theRequestDetails);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (outcome.getCreated() == Boolean.FALSE) {
|
||||||
|
updatedEntities.add(outcome.getEntity());
|
||||||
|
}
|
||||||
|
|
||||||
handleTransactionCreateOrUpdateOutcome(idSubstitutions, idToPersistedOutcome, nextResourceId, outcome, nextRespEntry, resourceType, res);
|
handleTransactionCreateOrUpdateOutcome(idSubstitutions, idToPersistedOutcome, nextResourceId, outcome, nextRespEntry, resourceType, res);
|
||||||
entriesToProcess.put(nextRespEntry, outcome.getEntity());
|
entriesToProcess.put(nextRespEntry, outcome.getEntity());
|
||||||
break;
|
break;
|
||||||
|
@ -435,12 +337,7 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle, MetaDt> {
|
||||||
* end.
|
* end.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
for (Iterator<DeleteConflict> iter = deleteConflicts.iterator(); iter.hasNext(); ) {
|
deleteConflicts.removeIf(next -> deletedResources.contains(next.getTargetId().toVersionless()));
|
||||||
DeleteConflict next = iter.next();
|
|
||||||
if (deletedResources.contains(next.getTargetId().toVersionless())) {
|
|
||||||
iter.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
validateDeleteConflictsEmptyOrThrowException(deleteConflicts);
|
validateDeleteConflictsEmptyOrThrowException(deleteConflicts);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -489,8 +386,9 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle, MetaDt> {
|
||||||
|
|
||||||
InstantDt deletedInstantOrNull = ResourceMetadataKeyEnum.DELETED_AT.get(nextResource);
|
InstantDt deletedInstantOrNull = ResourceMetadataKeyEnum.DELETED_AT.get(nextResource);
|
||||||
Date deletedTimestampOrNull = deletedInstantOrNull != null ? deletedInstantOrNull.getValue() : null;
|
Date deletedTimestampOrNull = deletedInstantOrNull != null ? deletedInstantOrNull.getValue() : null;
|
||||||
boolean shouldUpdate = !nonUpdatedEntities.contains(nextOutcome.getEntity());
|
if (updatedEntities.contains(nextOutcome.getEntity())) {
|
||||||
if (shouldUpdate) {
|
updateInternal(nextResource, true, false, theRequestDetails, nextOutcome.getEntity(), nextResource.getIdElement(), nextOutcome.getPreviousResource());
|
||||||
|
} else if (!nonUpdatedEntities.contains(nextOutcome.getEntity())) {
|
||||||
updateEntity(nextResource, nextOutcome.getEntity(), deletedTimestampOrNull, true, false, updateTime, false, true);
|
updateEntity(nextResource, nextOutcome.getEntity(), deletedTimestampOrNull, true, false, updateTime, false, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -603,12 +501,121 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle, MetaDt> {
|
||||||
long delay = System.currentTimeMillis() - start;
|
long delay = System.currentTimeMillis() - start;
|
||||||
int numEntries = theRequest.getEntry().size();
|
int numEntries = theRequest.getEntry().size();
|
||||||
long delayPer = delay / numEntries;
|
long delayPer = delay / numEntries;
|
||||||
ourLog.info("{} completed in {}ms ({} entries at {}ms per entry)", new Object[] { theActionName , delay, numEntries, delayPer });
|
ourLog.info("{} completed in {}ms ({} entries at {}ms per entry)", new Object[] {theActionName, delay, numEntries, delayPer});
|
||||||
|
|
||||||
response.setType(BundleTypeEnum.TRANSACTION_RESPONSE);
|
response.setType(BundleTypeEnum.TRANSACTION_RESPONSE);
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String extractTransactionUrlOrThrowException(Entry nextEntry, HTTPVerbEnum verb) {
|
||||||
|
String url = nextEntry.getRequest().getUrl();
|
||||||
|
if (isBlank(url)) {
|
||||||
|
throw new InvalidRequestException(getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionMissingUrl", verb.name()));
|
||||||
|
}
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called for nested bundles (e.g. if we received a transaction with an entry that
|
||||||
|
* was a GET search, this method is called on the bundle for the search result, that will be placed in the
|
||||||
|
* outer bundle). This method applies the _summary and _content parameters to the output of
|
||||||
|
* that bundle.
|
||||||
|
* <p>
|
||||||
|
* TODO: This isn't the most efficient way of doing this.. hopefully we can come up with something better in the future.
|
||||||
|
*/
|
||||||
|
private IBaseResource filterNestedBundle(RequestDetails theRequestDetails, IBaseResource theResource) {
|
||||||
|
IParser p = getContext().newJsonParser();
|
||||||
|
RestfulServerUtils.configureResponseParser(theRequestDetails, p);
|
||||||
|
return p.parseResource(theResource.getClass(), p.encodeResourceToString(theResource));
|
||||||
|
}
|
||||||
|
|
||||||
|
private IFhirResourceDao<?> getDaoOrThrowException(Class<? extends IResource> theClass) {
|
||||||
|
IFhirResourceDao<? extends IResource> retVal = getDao(theClass);
|
||||||
|
if (retVal == null) {
|
||||||
|
throw new InvalidRequestException("Unable to process request, this server does not know how to handle resources of type " + getContext().getResourceDefinition(theClass).getName());
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MetaDt metaGetOperation(RequestDetails theRequestDetails) {
|
||||||
|
// Notify interceptors
|
||||||
|
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails);
|
||||||
|
notifyInterceptors(RestOperationTypeEnum.META, requestDetails);
|
||||||
|
|
||||||
|
String sql = "SELECT d FROM TagDefinition d WHERE d.myId IN (SELECT DISTINCT t.myTagId FROM ResourceTag t)";
|
||||||
|
TypedQuery<TagDefinition> q = myEntityManager.createQuery(sql, TagDefinition.class);
|
||||||
|
List<TagDefinition> tagDefinitions = q.getResultList();
|
||||||
|
|
||||||
|
MetaDt retVal = toMetaDt(tagDefinitions);
|
||||||
|
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ca.uhn.fhir.jpa.dao.IFhirResourceDao<? extends IBaseResource> toDao(UrlParts theParts, String theVerb, String theUrl) {
|
||||||
|
RuntimeResourceDefinition resType;
|
||||||
|
try {
|
||||||
|
resType = getContext().getResourceDefinition(theParts.getResourceType());
|
||||||
|
} catch (DataFormatException e) {
|
||||||
|
String msg = getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionInvalidUrl", theVerb, theUrl);
|
||||||
|
throw new InvalidRequestException(msg);
|
||||||
|
}
|
||||||
|
IFhirResourceDao<? extends IBaseResource> dao = null;
|
||||||
|
if (resType != null) {
|
||||||
|
dao = getDao(resType.getImplementingClass());
|
||||||
|
}
|
||||||
|
if (dao == null) {
|
||||||
|
String msg = getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionInvalidUrl", theVerb, theUrl);
|
||||||
|
throw new InvalidRequestException(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (theParts.getResourceId() == null && theParts.getParams() == null) {
|
||||||
|
// String msg = getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionInvalidUrl", theVerb, theUrl);
|
||||||
|
// throw new InvalidRequestException(msg);
|
||||||
|
// }
|
||||||
|
|
||||||
|
return dao;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected MetaDt toMetaDt(Collection<TagDefinition> tagDefinitions) {
|
||||||
|
MetaDt retVal = new MetaDt();
|
||||||
|
for (TagDefinition next : tagDefinitions) {
|
||||||
|
switch (next.getTagType()) {
|
||||||
|
case PROFILE:
|
||||||
|
retVal.addProfile(next.getCode());
|
||||||
|
break;
|
||||||
|
case SECURITY_LABEL:
|
||||||
|
retVal.addSecurity().setSystem(next.getSystem()).setCode(next.getCode()).setDisplay(next.getDisplay());
|
||||||
|
break;
|
||||||
|
case TAG:
|
||||||
|
retVal.addTag().setSystem(next.getSystem()).setCode(next.getCode()).setDisplay(next.getDisplay());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(propagation = Propagation.REQUIRED)
|
||||||
|
@Override
|
||||||
|
public Bundle transaction(RequestDetails theRequestDetails, Bundle theRequest) {
|
||||||
|
if (theRequestDetails != null) {
|
||||||
|
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails, theRequest, "Bundle", null);
|
||||||
|
notifyInterceptors(RestOperationTypeEnum.TRANSACTION, requestDetails);
|
||||||
|
}
|
||||||
|
|
||||||
|
String actionName = "Transaction";
|
||||||
|
return transaction((ServletRequestDetails) theRequestDetails, theRequest, actionName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Bundle transaction(ServletRequestDetails theRequestDetails, Bundle theRequest, String theActionName) {
|
||||||
|
super.markRequestAsProcessingSubRequest(theRequestDetails);
|
||||||
|
try {
|
||||||
|
return doTransaction(theRequestDetails, theRequest, theActionName);
|
||||||
|
} finally {
|
||||||
|
super.clearRequestAsProcessingSubRequest(theRequestDetails);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static void handleTransactionCreateOrUpdateOutcome(Map<IdDt, IdDt> idSubstitutions, Map<IdDt, DaoMethodOutcome> idToPersistedOutcome, IdDt nextResourceId, DaoMethodOutcome outcome,
|
private static void handleTransactionCreateOrUpdateOutcome(Map<IdDt, IdDt> idSubstitutions, Map<IdDt, DaoMethodOutcome> idToPersistedOutcome, IdDt nextResourceId, DaoMethodOutcome outcome,
|
||||||
Entry newEntry, String theResourceType, IResource theRes) {
|
Entry newEntry, String theResourceType, IResource theRes) {
|
||||||
IdDt newId = (IdDt) outcome.getId().toUnqualifiedVersionless();
|
IdDt newId = (IdDt) outcome.getId().toUnqualifiedVersionless();
|
||||||
|
@ -645,9 +652,10 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle, MetaDt> {
|
||||||
}
|
}
|
||||||
|
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transaction Order, per the spec:
|
* Transaction Order, per the spec:
|
||||||
*
|
* <p>
|
||||||
* Process any DELETE interactions
|
* Process any DELETE interactions
|
||||||
* Process any POST interactions
|
* Process any POST interactions
|
||||||
* Process any PUT interactions
|
* Process any PUT interactions
|
||||||
|
|
|
@ -1193,7 +1193,7 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
codes = myTerminologySvc.findCodesBelow(system, code);
|
codes = myTerminologySvc.findCodesBelow(system, code);
|
||||||
}
|
}
|
||||||
|
|
||||||
ArrayList<Predicate> singleCodePredicates = new ArrayList<Predicate>();
|
ArrayList<Predicate> singleCodePredicates = new ArrayList<>();
|
||||||
if (codes != null) {
|
if (codes != null) {
|
||||||
|
|
||||||
if (codes.isEmpty()) {
|
if (codes.isEmpty()) {
|
||||||
|
@ -1581,7 +1581,8 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (valueSetUris.size() == 1) {
|
if (valueSetUris.size() == 1) {
|
||||||
List<VersionIndependentConcept> candidateCodes = myTerminologySvc.expandValueSet(valueSetUris.iterator().next());
|
String valueSet = valueSetUris.iterator().next();
|
||||||
|
List<VersionIndependentConcept> candidateCodes = myTerminologySvc.expandValueSet(valueSet);
|
||||||
for (VersionIndependentConcept nextCandidate : candidateCodes) {
|
for (VersionIndependentConcept nextCandidate : candidateCodes) {
|
||||||
if (nextCandidate.getCode().equals(code)) {
|
if (nextCandidate.getCode().equals(code)) {
|
||||||
retVal = nextCandidate.getSystem();
|
retVal = nextCandidate.getSystem();
|
||||||
|
|
|
@ -1,5 +1,12 @@
|
||||||
package ca.uhn.fhir.jpa.dao.data;
|
package ca.uhn.fhir.jpa.dao.data;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.jpa.entity.TermCodeSystem;
|
||||||
|
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
||||||
|
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;
|
import java.util.List;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -22,14 +29,12 @@ import java.util.List;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
|
||||||
import org.springframework.data.jpa.repository.Query;
|
|
||||||
import org.springframework.data.repository.query.Param;
|
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
|
||||||
|
|
||||||
public interface ITermCodeSystemVersionDao extends JpaRepository<TermCodeSystemVersion, Long> {
|
public interface ITermCodeSystemVersionDao extends JpaRepository<TermCodeSystemVersion, Long> {
|
||||||
|
|
||||||
|
@Modifying
|
||||||
|
@Query("DELETE FROM TermCodeSystemVersion csv WHERE csv.myCodeSystem = :cs")
|
||||||
|
void deleteForCodeSystem(@Param("cs") TermCodeSystem theCodeSystem);
|
||||||
|
|
||||||
@Query("SELECT cs FROM TermCodeSystemVersion cs WHERE cs.myResource.myId = :resource_id")
|
@Query("SELECT cs FROM TermCodeSystemVersion cs WHERE cs.myResource.myId = :resource_id")
|
||||||
List<TermCodeSystemVersion> findByCodeSystemResource(@Param("resource_id") Long theCodeSystemResourcePid);
|
List<TermCodeSystemVersion> findByCodeSystemResource(@Param("resource_id") Long theCodeSystemResourcePid);
|
||||||
|
|
||||||
|
|
|
@ -41,9 +41,9 @@ public interface ITermConceptDao extends JpaRepository<TermConcept, Long> {
|
||||||
@Query("SELECT c FROM TermConcept c WHERE c.myCodeSystem = :code_system")
|
@Query("SELECT c FROM TermConcept c WHERE c.myCodeSystem = :code_system")
|
||||||
List<TermConcept> findByCodeSystemVersion(@Param("code_system") TermCodeSystemVersion theCodeSystem);
|
List<TermConcept> findByCodeSystemVersion(@Param("code_system") TermCodeSystemVersion theCodeSystem);
|
||||||
|
|
||||||
@Query("DELETE FROM TermConcept t WHERE t.myCodeSystem.myId = :cs_pid")
|
@Query("SELECT t FROM TermConcept t WHERE t.myCodeSystem.myId = :cs_pid")
|
||||||
@Modifying
|
@Modifying
|
||||||
void deleteByCodeSystemVersion(@Param("cs_pid") Long thePid);
|
List<TermConcept> findByCodeSystemVersion(@Param("cs_pid") Long thePid);
|
||||||
|
|
||||||
@Query("UPDATE TermConcept t SET t.myIndexStatus = null")
|
@Query("UPDATE TermConcept t SET t.myIndexStatus = null")
|
||||||
@Modifying
|
@Modifying
|
||||||
|
|
|
@ -158,13 +158,11 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||||
|
|
||||||
ourLog.debug("Beginning {} with {} resources", theActionName, theRequest.getEntry().size());
|
ourLog.debug("Beginning {} with {} resources", theActionName, theRequest.getEntry().size());
|
||||||
|
|
||||||
// long start = System.currentTimeMillis();
|
|
||||||
final StopWatch transactionSw = new StopWatch();
|
|
||||||
final Date updateTime = new Date();
|
final Date updateTime = new Date();
|
||||||
|
|
||||||
final Set<IdType> allIds = new LinkedHashSet<IdType>();
|
final Set<IdType> allIds = new LinkedHashSet<>();
|
||||||
final Map<IdType, IdType> idSubstitutions = new HashMap<IdType, IdType>();
|
final Map<IdType, IdType> idSubstitutions = new HashMap<>();
|
||||||
final Map<IdType, DaoMethodOutcome> idToPersistedOutcome = new HashMap<IdType, DaoMethodOutcome>();
|
final Map<IdType, DaoMethodOutcome> idToPersistedOutcome = new HashMap<>();
|
||||||
|
|
||||||
// Do all entries have a verb?
|
// Do all entries have a verb?
|
||||||
for (int i = 0; i < theRequest.getEntry().size(); i++) {
|
for (int i = 0; i < theRequest.getEntry().size(); i++) {
|
||||||
|
@ -223,7 +221,7 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||||
Map<BundleEntryComponent, ResourceTable> entriesToProcess = txManager.execute(new TransactionCallback<Map<BundleEntryComponent, ResourceTable>>() {
|
Map<BundleEntryComponent, ResourceTable> entriesToProcess = txManager.execute(new TransactionCallback<Map<BundleEntryComponent, ResourceTable>>() {
|
||||||
@Override
|
@Override
|
||||||
public Map<BundleEntryComponent, ResourceTable> doInTransaction(TransactionStatus status) {
|
public Map<BundleEntryComponent, ResourceTable> doInTransaction(TransactionStatus status) {
|
||||||
return doTransactionWriteOperations(theRequestDetails, theRequest, theActionName, updateTime, allIds, idSubstitutions, idToPersistedOutcome, response, originalRequestOrder, entries, transactionSw);
|
return doTransactionWriteOperations(theRequestDetails, theRequest, theActionName, updateTime, allIds, idSubstitutions, idToPersistedOutcome, response, originalRequestOrder, entries);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
for (Entry<BundleEntryComponent, ResourceTable> nextEntry : entriesToProcess.entrySet()) {
|
for (Entry<BundleEntryComponent, ResourceTable> nextEntry : entriesToProcess.entrySet()) {
|
||||||
|
@ -300,20 +298,17 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ourLog.info(theActionName + " completed in {}", transactionSw.toString());
|
|
||||||
ourLog.info(theActionName + " details:\n{}", transactionSw.formatTaskDurations());
|
|
||||||
|
|
||||||
response.setType(BundleType.TRANSACTIONRESPONSE);
|
response.setType(BundleType.TRANSACTIONRESPONSE);
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
private Map<BundleEntryComponent, ResourceTable> doTransactionWriteOperations(ServletRequestDetails theRequestDetails, Bundle theRequest, String theActionName, Date theUpdateTime, Set<IdType> theAllIds,
|
||||||
private Map<BundleEntryComponent, ResourceTable> doTransactionWriteOperations(ServletRequestDetails theRequestDetails, Bundle theRequest, String theActionName, Date updateTime, Set<IdType> allIds,
|
Map<IdType, IdType> theIdSubstitutions, Map<IdType, DaoMethodOutcome> theIdToPersistedOutcome, Bundle theResponse, IdentityHashMap<BundleEntryComponent, Integer> theOriginalRequestOrder, List<BundleEntryComponent> theEntries) {
|
||||||
Map<IdType, IdType> theIdSubstitutions, Map<IdType, DaoMethodOutcome> idToPersistedOutcome, Bundle response, IdentityHashMap<BundleEntryComponent, Integer> originalRequestOrder, List<BundleEntryComponent> theEntries, StopWatch theStopWatch) {
|
|
||||||
Set<String> deletedResources = new HashSet<>();
|
Set<String> deletedResources = new HashSet<>();
|
||||||
List<DeleteConflict> deleteConflicts = new ArrayList<>();
|
List<DeleteConflict> deleteConflicts = new ArrayList<>();
|
||||||
Map<BundleEntryComponent, ResourceTable> entriesToProcess = new IdentityHashMap<>();
|
Map<BundleEntryComponent, ResourceTable> entriesToProcess = new IdentityHashMap<>();
|
||||||
Set<ResourceTable> nonUpdatedEntities = new HashSet<>();
|
Set<ResourceTable> nonUpdatedEntities = new HashSet<>();
|
||||||
|
Set<ResourceTable> updatedEntities = new HashSet<>();
|
||||||
Map<String, Class<? extends IBaseResource>> conditionalRequestUrls = new HashMap<>();
|
Map<String, Class<? extends IBaseResource>> conditionalRequestUrls = new HashMap<>();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -333,7 +328,7 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||||
|
|
||||||
nextResourceId = res.getIdElement();
|
nextResourceId = res.getIdElement();
|
||||||
|
|
||||||
if (nextResourceId.hasIdPart() == false) {
|
if (!nextResourceId.hasIdPart()) {
|
||||||
if (isNotBlank(nextReqEntry.getFullUrl())) {
|
if (isNotBlank(nextReqEntry.getFullUrl())) {
|
||||||
nextResourceId = new IdType(nextReqEntry.getFullUrl());
|
nextResourceId = new IdType(nextReqEntry.getFullUrl());
|
||||||
}
|
}
|
||||||
|
@ -352,12 +347,12 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||||
* Ensure that the bundle doesn't have any duplicates, since this causes all kinds of weirdness
|
* Ensure that the bundle doesn't have any duplicates, since this causes all kinds of weirdness
|
||||||
*/
|
*/
|
||||||
if (isPlaceholder(nextResourceId)) {
|
if (isPlaceholder(nextResourceId)) {
|
||||||
if (!allIds.add(nextResourceId)) {
|
if (!theAllIds.add(nextResourceId)) {
|
||||||
throw new InvalidRequestException(getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionContainsMultipleWithDuplicateId", nextResourceId));
|
throw new InvalidRequestException(getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionContainsMultipleWithDuplicateId", nextResourceId));
|
||||||
}
|
}
|
||||||
} else if (nextResourceId.hasResourceType() && nextResourceId.hasIdPart()) {
|
} else if (nextResourceId.hasResourceType() && nextResourceId.hasIdPart()) {
|
||||||
IdType nextId = nextResourceId.toUnqualifiedVersionless();
|
IdType nextId = nextResourceId.toUnqualifiedVersionless();
|
||||||
if (!allIds.add(nextId)) {
|
if (!theAllIds.add(nextId)) {
|
||||||
throw new InvalidRequestException(getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionContainsMultipleWithDuplicateId", nextId));
|
throw new InvalidRequestException(getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionContainsMultipleWithDuplicateId", nextId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -367,9 +362,7 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||||
HTTPVerb verb = nextReqEntry.getRequest().getMethodElement().getValue();
|
HTTPVerb verb = nextReqEntry.getRequest().getMethodElement().getValue();
|
||||||
|
|
||||||
String resourceType = res != null ? getContext().getResourceDefinition(res).getName() : null;
|
String resourceType = res != null ? getContext().getResourceDefinition(res).getName() : null;
|
||||||
BundleEntryComponent nextRespEntry = response.getEntry().get(originalRequestOrder.get(nextReqEntry));
|
BundleEntryComponent nextRespEntry = theResponse.getEntry().get(theOriginalRequestOrder.get(nextReqEntry));
|
||||||
|
|
||||||
theStopWatch.startTask("Process entry " + i + ": " + verb + " " + defaultString(resourceType));
|
|
||||||
|
|
||||||
switch (verb) {
|
switch (verb) {
|
||||||
case POST: {
|
case POST: {
|
||||||
|
@ -382,7 +375,7 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||||
matchUrl = performIdSubstitutionsInMatchUrl(theIdSubstitutions, matchUrl);
|
matchUrl = performIdSubstitutionsInMatchUrl(theIdSubstitutions, matchUrl);
|
||||||
outcome = resourceDao.create(res, matchUrl, false, theRequestDetails);
|
outcome = resourceDao.create(res, matchUrl, false, theRequestDetails);
|
||||||
if (nextResourceId != null) {
|
if (nextResourceId != null) {
|
||||||
handleTransactionCreateOrUpdateOutcome(theIdSubstitutions, idToPersistedOutcome, nextResourceId, outcome, nextRespEntry, resourceType, res, theRequestDetails);
|
handleTransactionCreateOrUpdateOutcome(theIdSubstitutions, theIdToPersistedOutcome, nextResourceId, outcome, nextRespEntry, resourceType, res, theRequestDetails);
|
||||||
}
|
}
|
||||||
entriesToProcess.put(nextRespEntry, outcome.getEntity());
|
entriesToProcess.put(nextRespEntry, outcome.getEntity());
|
||||||
if (outcome.getCreated() == false) {
|
if (outcome.getCreated() == false) {
|
||||||
|
@ -460,17 +453,20 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleTransactionCreateOrUpdateOutcome(theIdSubstitutions, idToPersistedOutcome, nextResourceId, outcome, nextRespEntry, resourceType, res, theRequestDetails);
|
if (outcome.getCreated() == Boolean.FALSE) {
|
||||||
|
updatedEntities.add(outcome.getEntity());
|
||||||
|
}
|
||||||
|
|
||||||
|
handleTransactionCreateOrUpdateOutcome(theIdSubstitutions, theIdToPersistedOutcome, nextResourceId, outcome, nextRespEntry, resourceType, res, theRequestDetails);
|
||||||
entriesToProcess.put(nextRespEntry, outcome.getEntity());
|
entriesToProcess.put(nextRespEntry, outcome.getEntity());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GET:
|
case GET:
|
||||||
case NULL:
|
case NULL:
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
theStopWatch.endCurrentTask();
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make sure that there are no conflicts from deletions. E.g. we can't delete something
|
* Make sure that there are no conflicts from deletions. E.g. we can't delete something
|
||||||
|
@ -479,12 +475,8 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||||
* end.
|
* end.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
for (Iterator<DeleteConflict> iter = deleteConflicts.iterator(); iter.hasNext();) {
|
deleteConflicts.removeIf(next ->
|
||||||
DeleteConflict next = iter.next();
|
deletedResources.contains(next.getTargetId().toUnqualifiedVersionless().getValue()));
|
||||||
if (deletedResources.contains(next.getTargetId().toUnqualifiedVersionless().getValue())) {
|
|
||||||
iter.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
validateDeleteConflictsEmptyOrThrowException(deleteConflicts);
|
validateDeleteConflictsEmptyOrThrowException(deleteConflicts);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -492,13 +484,13 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
FhirTerser terser = getContext().newTerser();
|
FhirTerser terser = getContext().newTerser();
|
||||||
for (DaoMethodOutcome nextOutcome : idToPersistedOutcome.values()) {
|
for (DaoMethodOutcome nextOutcome : theIdToPersistedOutcome.values()) {
|
||||||
IBaseResource nextResource = nextOutcome.getResource();
|
IBaseResource nextResource = nextOutcome.getResource();
|
||||||
if (nextResource == null) {
|
if (nextResource == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Refererences
|
// References
|
||||||
List<IBaseReference> allRefs = terser.getAllPopulatedChildElementsOfType(nextResource, IBaseReference.class);
|
List<IBaseReference> allRefs = terser.getAllPopulatedChildElementsOfType(nextResource, IBaseReference.class);
|
||||||
for (IBaseReference nextRef : allRefs) {
|
for (IBaseReference nextRef : allRefs) {
|
||||||
IIdType nextId = nextRef.getReferenceElement();
|
IIdType nextId = nextRef.getReferenceElement();
|
||||||
|
@ -534,18 +526,16 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||||
|
|
||||||
IPrimitiveType<Date> deletedInstantOrNull = ResourceMetadataKeyEnum.DELETED_AT.get((IAnyResource) nextResource);
|
IPrimitiveType<Date> deletedInstantOrNull = ResourceMetadataKeyEnum.DELETED_AT.get((IAnyResource) nextResource);
|
||||||
Date deletedTimestampOrNull = deletedInstantOrNull != null ? deletedInstantOrNull.getValue() : null;
|
Date deletedTimestampOrNull = deletedInstantOrNull != null ? deletedInstantOrNull.getValue() : null;
|
||||||
boolean shouldUpdate = !nonUpdatedEntities.contains(nextOutcome.getEntity());
|
|
||||||
if (shouldUpdate) {
|
|
||||||
updateEntity(nextResource, nextOutcome.getEntity(), deletedTimestampOrNull, shouldUpdate, false, updateTime, false, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
theStopWatch.startTask("Flush Session");
|
if (updatedEntities.contains(nextOutcome.getEntity())) {
|
||||||
|
updateInternal(nextResource, true, false, theRequestDetails, nextOutcome.getEntity(), nextResource.getIdElement(), nextOutcome.getPreviousResource());
|
||||||
|
} else if (!nonUpdatedEntities.contains(nextOutcome.getEntity())) {
|
||||||
|
updateEntity(nextResource, nextOutcome.getEntity(), deletedTimestampOrNull, true, false, theUpdateTime, false, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
flushJpaSession();
|
flushJpaSession();
|
||||||
|
|
||||||
theStopWatch.endCurrentTask();
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Double check we didn't allow any duplicates we shouldn't have
|
* Double check we didn't allow any duplicates we shouldn't have
|
||||||
*/
|
*/
|
||||||
|
@ -562,7 +552,7 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (IdType next : allIds) {
|
for (IdType next : theAllIds) {
|
||||||
IdType replacement = theIdSubstitutions.get(next);
|
IdType replacement = theIdSubstitutions.get(next);
|
||||||
if (replacement == null) {
|
if (replacement == null) {
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -19,6 +19,8 @@ import javax.transaction.Transactional.TxType;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* #%L
|
* #%L
|
||||||
* HAPI FHIR JPA Server
|
* HAPI FHIR JPA Server
|
||||||
|
@ -87,6 +89,9 @@ public class JpaValidationSupportDstu3 implements IJpaValidationSupportDstu3 {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CodeSystem fetchCodeSystem(FhirContext theCtx, String theSystem) {
|
public CodeSystem fetchCodeSystem(FhirContext theCtx, String theSystem) {
|
||||||
|
if (isBlank(theSystem)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return fetchResource(theCtx, CodeSystem.class, theSystem);
|
return fetchResource(theCtx, CodeSystem.class, theSystem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,6 @@ import ca.uhn.fhir.jpa.entity.ResourceTable;
|
||||||
import ca.uhn.fhir.jpa.entity.TagDefinition;
|
import ca.uhn.fhir.jpa.entity.TagDefinition;
|
||||||
import ca.uhn.fhir.jpa.provider.ServletSubRequestDetails;
|
import ca.uhn.fhir.jpa.provider.ServletSubRequestDetails;
|
||||||
import ca.uhn.fhir.jpa.util.DeleteConflict;
|
import ca.uhn.fhir.jpa.util.DeleteConflict;
|
||||||
import ca.uhn.fhir.util.StopWatch;
|
|
||||||
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
|
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
|
||||||
import ca.uhn.fhir.parser.DataFormatException;
|
import ca.uhn.fhir.parser.DataFormatException;
|
||||||
import ca.uhn.fhir.parser.IParser;
|
import ca.uhn.fhir.parser.IParser;
|
||||||
|
@ -266,7 +265,7 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||||
paramValues.put(next.getName(), next.getValue());
|
paramValues.put(next.getName(), next.getValue());
|
||||||
}
|
}
|
||||||
for (java.util.Map.Entry<String, Collection<String>> nextParamEntry : paramValues.asMap().entrySet()) {
|
for (java.util.Map.Entry<String, Collection<String>> nextParamEntry : paramValues.asMap().entrySet()) {
|
||||||
String[] nextValue = nextParamEntry.getValue().toArray(new String[ nextParamEntry.getValue().size() ]);
|
String[] nextValue = nextParamEntry.getValue().toArray(new String[nextParamEntry.getValue().size()]);
|
||||||
requestDetails.addParameter(nextParamEntry.getKey(), nextValue);
|
requestDetails.addParameter(nextParamEntry.getKey(), nextValue);
|
||||||
}
|
}
|
||||||
url = url.substring(0, qIndex);
|
url = url.substring(0, qIndex);
|
||||||
|
@ -323,6 +322,7 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||||
List<DeleteConflict> deleteConflicts = new ArrayList<>();
|
List<DeleteConflict> deleteConflicts = new ArrayList<>();
|
||||||
Map<BundleEntryComponent, ResourceTable> entriesToProcess = new IdentityHashMap<>();
|
Map<BundleEntryComponent, ResourceTable> entriesToProcess = new IdentityHashMap<>();
|
||||||
Set<ResourceTable> nonUpdatedEntities = new HashSet<>();
|
Set<ResourceTable> nonUpdatedEntities = new HashSet<>();
|
||||||
|
Set<ResourceTable> updatedEntities = new HashSet<>();
|
||||||
Map<String, Class<? extends IBaseResource>> conditionalRequestUrls = new HashMap<>();
|
Map<String, Class<? extends IBaseResource>> conditionalRequestUrls = new HashMap<>();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -467,6 +467,10 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (outcome.getCreated() == Boolean.FALSE) {
|
||||||
|
updatedEntities.add(outcome.getEntity());
|
||||||
|
}
|
||||||
|
|
||||||
handleTransactionCreateOrUpdateOutcome(theIdSubstitutions, theIdToPersistedOutcome, nextResourceId, outcome, nextRespEntry, resourceType, res, theRequestDetails);
|
handleTransactionCreateOrUpdateOutcome(theIdSubstitutions, theIdToPersistedOutcome, nextResourceId, outcome, nextRespEntry, resourceType, res, theRequestDetails);
|
||||||
entriesToProcess.put(nextRespEntry, outcome.getEntity());
|
entriesToProcess.put(nextRespEntry, outcome.getEntity());
|
||||||
break;
|
break;
|
||||||
|
@ -538,9 +542,11 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||||
|
|
||||||
IPrimitiveType<Date> deletedInstantOrNull = ResourceMetadataKeyEnum.DELETED_AT.get((IAnyResource) nextResource);
|
IPrimitiveType<Date> deletedInstantOrNull = ResourceMetadataKeyEnum.DELETED_AT.get((IAnyResource) nextResource);
|
||||||
Date deletedTimestampOrNull = deletedInstantOrNull != null ? deletedInstantOrNull.getValue() : null;
|
Date deletedTimestampOrNull = deletedInstantOrNull != null ? deletedInstantOrNull.getValue() : null;
|
||||||
boolean shouldUpdate = !nonUpdatedEntities.contains(nextOutcome.getEntity());
|
|
||||||
if (shouldUpdate) {
|
if (updatedEntities.contains(nextOutcome.getEntity())) {
|
||||||
updateEntity(nextResource, nextOutcome.getEntity(), deletedTimestampOrNull, shouldUpdate, false, theUpdateTime, false, true);
|
updateInternal(nextResource, true, false, theRequestDetails, nextOutcome.getEntity(), nextResource.getIdElement(), nextOutcome.getPreviousResource());
|
||||||
|
} else if (!nonUpdatedEntities.contains(nextOutcome.getEntity())) {
|
||||||
|
updateEntity(nextResource, nextOutcome.getEntity(), deletedTimestampOrNull, true, false, theUpdateTime, false, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ public abstract class BaseResourceIndexedSearchParam implements Serializable {
|
||||||
private Long myResourcePid;
|
private Long myResourcePid;
|
||||||
|
|
||||||
@Field()
|
@Field()
|
||||||
@Column(name = "RES_TYPE", nullable = false, length = 30)
|
@Column(name = "RES_TYPE", nullable = false)
|
||||||
private String myResourceType;
|
private String myResourceType;
|
||||||
|
|
||||||
@Field()
|
@Field()
|
||||||
|
|
|
@ -20,6 +20,9 @@ package ca.uhn.fhir.jpa.entity;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||||
|
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||||
|
|
||||||
import javax.persistence.*;
|
import javax.persistence.*;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
@ -89,4 +92,15 @@ public class TermCodeSystem implements Serializable {
|
||||||
public void setResource(ResourceTable theResource) {
|
public void setResource(ResourceTable theResource) {
|
||||||
myResource = theResource;
|
myResource = theResource;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
|
||||||
|
.append("codeSystemUri", myCodeSystemUri)
|
||||||
|
.append("currentVersion", myCurrentVersion)
|
||||||
|
.append("pid", myPid)
|
||||||
|
.append("resourcePid", myResourcePid)
|
||||||
|
.append("name", myName)
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@ public class TermCodeSystemVersion implements Serializable {
|
||||||
* issued. It should be made non-nullable at some point.
|
* issued. It should be made non-nullable at some point.
|
||||||
*/
|
*/
|
||||||
@ManyToOne
|
@ManyToOne
|
||||||
@JoinColumn(name = "CODESYSTEM_PID", referencedColumnName = "PID", nullable = true)
|
@JoinColumn(name = "CODESYSTEM_PID", referencedColumnName = "PID", nullable = true, foreignKey = @ForeignKey(name = "FK_CODESYSVER_CS_ID"))
|
||||||
private TermCodeSystem myCodeSystem;
|
private TermCodeSystem myCodeSystem;
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
@OneToOne(mappedBy = "myCurrentVersion", optional = true)
|
@OneToOne(mappedBy = "myCurrentVersion", optional = true)
|
||||||
|
|
|
@ -31,7 +31,7 @@ public class TermConceptDesignation implements Serializable {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
@ManyToOne
|
@ManyToOne
|
||||||
@JoinColumn(name = "CONCEPT_PID", referencedColumnName = "PID", foreignKey = @ForeignKey(name = "FK_CONCEPTPROP_CONCEPT"))
|
@JoinColumn(name = "CONCEPT_PID", referencedColumnName = "PID", foreignKey = @ForeignKey(name = "FK_CONCEPTDESIG_CONCEPT"))
|
||||||
private TermConcept myConcept;
|
private TermConcept myConcept;
|
||||||
@Id()
|
@Id()
|
||||||
@SequenceGenerator(name = "SEQ_CONCEPT_DESIG_PID", sequenceName = "SEQ_CONCEPT_DESIG_PID")
|
@SequenceGenerator(name = "SEQ_CONCEPT_DESIG_PID", sequenceName = "SEQ_CONCEPT_DESIG_PID")
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.jpa.entity;
|
package ca.uhn.fhir.jpa.entity;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%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 org.apache.lucene.document.Document;
|
import org.apache.lucene.document.Document;
|
||||||
import org.hibernate.search.bridge.FieldBridge;
|
import org.hibernate.search.bridge.FieldBridge;
|
||||||
import org.hibernate.search.bridge.LuceneOptions;
|
import org.hibernate.search.bridge.LuceneOptions;
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.jpa.entity;
|
package ca.uhn.fhir.jpa.entity;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%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%
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see TermConceptProperty#getType()
|
* @see TermConceptProperty#getType()
|
||||||
* @see TermConceptProperty#MAX_PROPTYPE_ENUM_LENGTH
|
* @see TermConceptProperty#MAX_PROPTYPE_ENUM_LENGTH
|
||||||
|
|
|
@ -22,47 +22,47 @@ package ca.uhn.fhir.jpa.provider;
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
|
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
|
||||||
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc.UploadStatistics;
|
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.api.server.RequestDetails;
|
||||||
import ca.uhn.fhir.rest.param.StringParam;
|
import ca.uhn.fhir.rest.param.StringParam;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||||
|
import org.hl7.fhir.r4.model.Attachment;
|
||||||
import org.hl7.fhir.r4.model.IntegerType;
|
import org.hl7.fhir.r4.model.IntegerType;
|
||||||
import org.hl7.fhir.r4.model.Parameters;
|
import org.hl7.fhir.r4.model.Parameters;
|
||||||
import org.hl7.fhir.r4.model.StringType;
|
import org.hl7.fhir.r4.model.StringType;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import java.io.File;
|
import java.io.*;
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.apache.commons.lang3.StringUtils.defaultString;
|
import static org.apache.commons.lang3.StringUtils.*;
|
||||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
|
||||||
|
|
||||||
public class TerminologyUploaderProvider extends BaseJpaProvider {
|
public abstract class BaseTerminologyUploaderProvider extends BaseJpaProvider {
|
||||||
public static final String UPLOAD_EXTERNAL_CODE_SYSTEM = "$upload-external-code-system";
|
public static final String UPLOAD_EXTERNAL_CODE_SYSTEM = "$upload-external-code-system";
|
||||||
|
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TerminologyUploaderProvider.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseTerminologyUploaderProvider.class);
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IHapiTerminologyLoaderSvc myTerminologyLoaderSvc;
|
private IHapiTerminologyLoaderSvc myTerminologyLoaderSvc;
|
||||||
|
|
||||||
@Operation(name = UPLOAD_EXTERNAL_CODE_SYSTEM, idempotent = false, returnParameters= {
|
protected Parameters handleUploadExternalCodeSystem(
|
||||||
@OperationParam(name="conceptCount", type=IntegerType.class, min=1)
|
|
||||||
})
|
|
||||||
public Parameters uploadExternalCodeSystem(
|
|
||||||
HttpServletRequest theServletRequest,
|
HttpServletRequest theServletRequest,
|
||||||
@OperationParam(name="url", min=1) StringParam theCodeSystemUrl,
|
StringParam theCodeSystemUrl,
|
||||||
@OperationParam(name="localfile", min=1, max=OperationParam.MAX_UNLIMITED) List<StringType> theLocalFile,
|
List<StringType> theLocalFile,
|
||||||
RequestDetails theRequestDetails
|
List<Attachment> thePackage, RequestDetails theRequestDetails
|
||||||
) {
|
) {
|
||||||
|
|
||||||
startRequest(theServletRequest);
|
startRequest(theServletRequest);
|
||||||
|
|
||||||
|
if (theLocalFile == null || theLocalFile.size() == 0) {
|
||||||
|
if (thePackage == null || thePackage.size() == 0) {
|
||||||
|
throw new InvalidRequestException("No 'localfile' or 'package' parameter, or package had no data");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
List<IHapiTerminologyLoaderSvc.FileDescriptor> localFiles = new ArrayList<>();
|
List<IHapiTerminologyLoaderSvc.FileDescriptor> localFiles = new ArrayList<>();
|
||||||
if (theLocalFile != null && theLocalFile.size() > 0) {
|
if (theLocalFile != null && theLocalFile.size() > 0) {
|
||||||
|
@ -70,8 +70,8 @@ public class TerminologyUploaderProvider extends BaseJpaProvider {
|
||||||
if (isNotBlank(nextLocalFile.getValue())) {
|
if (isNotBlank(nextLocalFile.getValue())) {
|
||||||
ourLog.info("Reading in local file: {}", nextLocalFile.getValue());
|
ourLog.info("Reading in local file: {}", nextLocalFile.getValue());
|
||||||
File nextFile = new File(nextLocalFile.getValue());
|
File nextFile = new File(nextLocalFile.getValue());
|
||||||
if (!nextFile.exists() || nextFile.isFile()) {
|
if (!nextFile.exists() || !nextFile.isFile()) {
|
||||||
throw new InvalidRequestException("Unknown file: " +nextFile.getName());
|
throw new InvalidRequestException("Unknown file: " + nextFile.getName());
|
||||||
}
|
}
|
||||||
localFiles.add(new IHapiTerminologyLoaderSvc.FileDescriptor() {
|
localFiles.add(new IHapiTerminologyLoaderSvc.FileDescriptor() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -92,6 +92,26 @@ public class TerminologyUploaderProvider extends BaseJpaProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (thePackage != null) {
|
||||||
|
for (Attachment nextPackage : thePackage) {
|
||||||
|
if (isBlank(nextPackage.getUrl())) {
|
||||||
|
throw new UnprocessableEntityException("Package is missing mandatory url element");
|
||||||
|
}
|
||||||
|
|
||||||
|
localFiles.add(new IHapiTerminologyLoaderSvc.FileDescriptor() {
|
||||||
|
@Override
|
||||||
|
public String getFilename() {
|
||||||
|
return nextPackage.getUrl();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputStream getInputStream() {
|
||||||
|
return new ByteArrayInputStream(nextPackage.getData());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
String url = theCodeSystemUrl != null ? theCodeSystemUrl.getValue() : null;
|
String url = theCodeSystemUrl != null ? theCodeSystemUrl.getValue() : null;
|
||||||
url = defaultString(url);
|
url = defaultString(url);
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
package ca.uhn.fhir.jpa.provider.dstu3;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%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 ca.uhn.fhir.jpa.provider.BaseTerminologyUploaderProvider;
|
||||||
|
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 org.hl7.fhir.convertors.VersionConvertor_30_40;
|
||||||
|
import org.hl7.fhir.dstu3.model.Attachment;
|
||||||
|
import org.hl7.fhir.dstu3.model.IntegerType;
|
||||||
|
import org.hl7.fhir.dstu3.model.Parameters;
|
||||||
|
import org.hl7.fhir.dstu3.model.StringType;
|
||||||
|
import org.hl7.fhir.exceptions.FHIRException;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class TerminologyUploaderProviderDstu3 extends BaseTerminologyUploaderProvider {
|
||||||
|
|
||||||
|
@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) StringParam theCodeSystemUrl,
|
||||||
|
@OperationParam(name = "localfile", min = 1, max = OperationParam.MAX_UNLIMITED) List<StringType> theLocalFile,
|
||||||
|
@OperationParam(name = "package", min = 0, max = OperationParam.MAX_UNLIMITED) List<Attachment> thePackage,
|
||||||
|
RequestDetails theRequestDetails
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
List<org.hl7.fhir.r4.model.StringType> localFile = null;
|
||||||
|
if (theLocalFile != null) {
|
||||||
|
localFile = new ArrayList<>();
|
||||||
|
for (StringType next : theLocalFile) {
|
||||||
|
localFile.add(VersionConvertor_30_40.convertString(next));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
List<org.hl7.fhir.r4.model.Attachment> pkg = null;
|
||||||
|
if (thePackage!=null){
|
||||||
|
pkg = new ArrayList<>();
|
||||||
|
for (Attachment next : thePackage) {
|
||||||
|
pkg.add(VersionConvertor_30_40.convertAttachment(next));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
org.hl7.fhir.r4.model.Parameters retValR4 = handleUploadExternalCodeSystem(theServletRequest, theCodeSystemUrl, localFile, pkg, theRequestDetails);
|
||||||
|
return VersionConvertor_30_40.convertParameters(retValR4);
|
||||||
|
} catch (FHIRException e) {
|
||||||
|
throw new InternalErrorException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
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 ca.uhn.fhir.jpa.provider.BaseTerminologyUploaderProvider;
|
||||||
|
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 org.hl7.fhir.r4.model.Attachment;
|
||||||
|
import org.hl7.fhir.r4.model.IntegerType;
|
||||||
|
import org.hl7.fhir.r4.model.Parameters;
|
||||||
|
import org.hl7.fhir.r4.model.StringType;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class TerminologyUploaderProviderR4 extends BaseTerminologyUploaderProvider {
|
||||||
|
|
||||||
|
@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) StringParam theCodeSystemUrl,
|
||||||
|
@OperationParam(name = "localfile", min = 1, max = OperationParam.MAX_UNLIMITED) List<StringType> theLocalFile,
|
||||||
|
@OperationParam(name = "package", min = 0, max = OperationParam.MAX_UNLIMITED) List<Attachment> thePackage,
|
||||||
|
RequestDetails theRequestDetails
|
||||||
|
) {
|
||||||
|
return handleUploadExternalCodeSystem(theServletRequest, theCodeSystemUrl, theLocalFile, thePackage, theRequestDetails);
|
||||||
|
}
|
||||||
|
}
|
|
@ -105,6 +105,15 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc
|
||||||
contains.setCode(theConcept.getCode());
|
contains.setCode(theConcept.getCode());
|
||||||
contains.setSystem(theCodeSystem);
|
contains.setSystem(theCodeSystem);
|
||||||
contains.setDisplay(theConcept.getDisplay());
|
contains.setDisplay(theConcept.getDisplay());
|
||||||
|
for (TermConceptDesignation nextDesignation : theConcept.getDesignations()) {
|
||||||
|
contains
|
||||||
|
.addDesignation()
|
||||||
|
.setValue(nextDesignation.getValue())
|
||||||
|
.getUse()
|
||||||
|
.setSystem(nextDesignation.getUseSystem())
|
||||||
|
.setCode(nextDesignation.getUseCode())
|
||||||
|
.setDisplay(nextDesignation.getUseDisplay());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,11 +241,13 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc
|
||||||
haveIncludeCriteria = true;
|
haveIncludeCriteria = true;
|
||||||
TermConcept code = findCode(system, nextCode);
|
TermConcept code = findCode(system, nextCode);
|
||||||
if (code != null) {
|
if (code != null) {
|
||||||
addedCodes.add(nextCode);
|
addCodeIfNotAlreadyAdded(system, expansionComponent, addedCodes, code);
|
||||||
ValueSet.ValueSetExpansionContainsComponent contains = expansionComponent.addContains();
|
//
|
||||||
contains.setCode(nextCode);
|
// addedCodes.add(nextCode);
|
||||||
contains.setSystem(system);
|
// ValueSet.ValueSetExpansionContainsComponent contains = expansionComponent.addContains();
|
||||||
contains.setDisplay(code.getDisplay());
|
// contains.setCode(nextCode);
|
||||||
|
// contains.setSystem(system);
|
||||||
|
// contains.setDisplay(code.getDisplay());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,6 +76,11 @@ public class HapiTerminologySvcDstu2 extends BaseHapiTerminologySvcImpl {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected CodeSystem getCodeSystemFromContext(String theSystem) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<VersionIndependentConcept> expandValueSet(String theValueSet) {
|
public List<VersionIndependentConcept> expandValueSet(String theValueSet) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
|
|
|
@ -153,6 +153,24 @@ public class HapiTerminologySvcDstu3 extends BaseHapiTerminologySvcImpl implemen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<VersionIndependentConcept> expandValueSet(String theValueSet) {
|
||||||
|
ValueSet vs = myValidationSupport.fetchResource(myContext, ValueSet.class, theValueSet);
|
||||||
|
if (vs == null) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
org.hl7.fhir.r4.model.ValueSet valueSetToExpandR4;
|
||||||
|
try {
|
||||||
|
valueSetToExpandR4 = VersionConvertor_30_40.convertValueSet(vs);
|
||||||
|
} catch (FHIRException e) {
|
||||||
|
throw new InternalErrorException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return expandValueSetAndReturnVersionIndependentConcepts(valueSetToExpandR4);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<IBaseResource> fetchAllConformanceResources(FhirContext theContext) {
|
public List<IBaseResource> fetchAllConformanceResources(FhirContext theContext) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -222,6 +240,16 @@ public class HapiTerminologySvcDstu3 extends BaseHapiTerminologySvcImpl implemen
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected org.hl7.fhir.r4.model.CodeSystem getCodeSystemFromContext(String theSystem) {
|
||||||
|
CodeSystem codeSystem = myValidationSupport.fetchCodeSystem(myContext, theSystem);
|
||||||
|
try {
|
||||||
|
return VersionConvertor_30_40.convertCodeSystem(codeSystem);
|
||||||
|
} catch (FHIRException e) {
|
||||||
|
throw new InternalErrorException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isCodeSystemSupported(FhirContext theContext, String theSystem) {
|
public boolean isCodeSystemSupported(FhirContext theContext, String theSystem) {
|
||||||
return myTerminologySvc.supportsSystem(theSystem);
|
return myTerminologySvc.supportsSystem(theSystem);
|
||||||
|
|
|
@ -112,6 +112,16 @@ public class HapiTerminologySvcR4 extends BaseHapiTerminologySvcImpl implements
|
||||||
myValueSetResourceDao.update(theValueSet, matchUrl, theRequestDetails);
|
myValueSetResourceDao.update(theValueSet, matchUrl, theRequestDetails);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<VersionIndependentConcept> expandValueSet(String theValueSet) {
|
||||||
|
ValueSet vs = myValidationSupport.fetchResource(myContext, ValueSet.class, theValueSet);
|
||||||
|
if (vs == null) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
return expandValueSetAndReturnVersionIndependentConcepts(vs);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ValueSetExpansionComponent expandValueSet(FhirContext theContext, ConceptSetComponent theInclude) {
|
public ValueSetExpansionComponent expandValueSet(FhirContext theContext, ConceptSetComponent theInclude) {
|
||||||
ValueSet valueSetToExpand = new ValueSet();
|
ValueSet valueSetToExpand = new ValueSet();
|
||||||
|
@ -188,6 +198,11 @@ public class HapiTerminologySvcR4 extends BaseHapiTerminologySvcImpl implements
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected CodeSystem getCodeSystemFromContext(String theSystem) {
|
||||||
|
return myValidationSupport.fetchCodeSystem(myContext, theSystem);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isCodeSystemSupported(FhirContext theContext, String theSystem) {
|
public boolean isCodeSystemSupported(FhirContext theContext, String theSystem) {
|
||||||
return myTerminologySvc.supportsSystem(theSystem);
|
return myTerminologySvc.supportsSystem(theSystem);
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.jpa.term;
|
package ca.uhn.fhir.jpa.term;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%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 org.apache.commons.csv.CSVRecord;
|
import org.apache.commons.csv.CSVRecord;
|
||||||
|
|
||||||
public interface IRecordHandler {
|
public interface IRecordHandler {
|
||||||
|
|
|
@ -128,6 +128,13 @@ public class TerminologyLoaderSvcImpl implements IHapiTerminologyLoaderSvc {
|
||||||
CSVParser parsed;
|
CSVParser parsed;
|
||||||
try {
|
try {
|
||||||
reader = new InputStreamReader(nextZipBytes.getInputStream(), Charsets.UTF_8);
|
reader = new InputStreamReader(nextZipBytes.getInputStream(), Charsets.UTF_8);
|
||||||
|
|
||||||
|
if (ourLog.isTraceEnabled()) {
|
||||||
|
String contents = IOUtils.toString(reader);
|
||||||
|
ourLog.info("File contents for: {}\n{}", nextFilename, contents);
|
||||||
|
reader = new StringReader(contents);
|
||||||
|
}
|
||||||
|
|
||||||
CSVFormat format = CSVFormat.newFormat(theDelimiter).withFirstRecordAsHeader();
|
CSVFormat format = CSVFormat.newFormat(theDelimiter).withFirstRecordAsHeader();
|
||||||
if (theQuoteMode != null) {
|
if (theQuoteMode != null) {
|
||||||
format = format.withQuote('"').withQuoteMode(theQuoteMode);
|
format = format.withQuote('"').withQuoteMode(theQuoteMode);
|
||||||
|
@ -402,16 +409,15 @@ public class TerminologyLoaderSvcImpl implements IHapiTerminologyLoaderSvc {
|
||||||
LoadedFileDescriptors(List<IHapiTerminologyLoaderSvc.FileDescriptor> theFileDescriptors) {
|
LoadedFileDescriptors(List<IHapiTerminologyLoaderSvc.FileDescriptor> theFileDescriptors) {
|
||||||
try {
|
try {
|
||||||
for (FileDescriptor next : theFileDescriptors) {
|
for (FileDescriptor next : theFileDescriptors) {
|
||||||
File nextTemporaryFile = File.createTempFile("hapifhir", ".tmp");
|
|
||||||
nextTemporaryFile.deleteOnExit();
|
|
||||||
|
|
||||||
if (next.getFilename().toLowerCase().endsWith(".zip")) {
|
if (next.getFilename().toLowerCase().endsWith(".zip")) {
|
||||||
ourLog.info("Uncompressing {} into temporary files", next.getFilename());
|
ourLog.info("Uncompressing {} into temporary files", next.getFilename());
|
||||||
try (InputStream inputStream = next.getInputStream()) {
|
try (InputStream inputStream = next.getInputStream()) {
|
||||||
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(inputStream));
|
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(inputStream));
|
||||||
for (ZipEntry nextEntry; (nextEntry = zis.getNextEntry()) != null; ) {
|
for (ZipEntry nextEntry; (nextEntry = zis.getNextEntry()) != null; ) {
|
||||||
BOMInputStream fis = new BOMInputStream(zis);
|
BOMInputStream fis = new BOMInputStream(zis);
|
||||||
FileOutputStream fos = new FileOutputStream(nextTemporaryFile);
|
File nextTemporaryFile = File.createTempFile("hapifhir", ".tmp");
|
||||||
|
nextTemporaryFile.deleteOnExit();
|
||||||
|
FileOutputStream fos = new FileOutputStream(nextTemporaryFile, false);
|
||||||
IOUtils.copy(fis, fos);
|
IOUtils.copy(fis, fos);
|
||||||
String nextEntryFileName = nextEntry.getName();
|
String nextEntryFileName = nextEntry.getName();
|
||||||
myUncompressedFileDescriptors.add(new FileDescriptor() {
|
myUncompressedFileDescriptors.add(new FileDescriptor() {
|
||||||
|
|
|
@ -25,6 +25,16 @@ public class VersionIndependentConcept {
|
||||||
private String mySystem;
|
private String mySystem;
|
||||||
private String myCode;
|
private String myCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
public VersionIndependentConcept() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
public VersionIndependentConcept(String theSystem, String theCode) {
|
public VersionIndependentConcept(String theSystem, String theCode) {
|
||||||
setSystem(theSystem);
|
setSystem(theSystem);
|
||||||
setCode(theCode);
|
setCode(theCode);
|
||||||
|
@ -34,16 +44,18 @@ public class VersionIndependentConcept {
|
||||||
return mySystem;
|
return mySystem;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSystem(String theSystem) {
|
public VersionIndependentConcept setSystem(String theSystem) {
|
||||||
mySystem = theSystem;
|
mySystem = theSystem;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getCode() {
|
public String getCode() {
|
||||||
return myCode;
|
return myCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCode(String theCode) {
|
public VersionIndependentConcept setCode(String theCode) {
|
||||||
myCode = theCode;
|
myCode = theCode;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.jpa.term.loinc;
|
package ca.uhn.fhir.jpa.term.loinc;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%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 ca.uhn.fhir.jpa.entity.TermConcept;
|
import ca.uhn.fhir.jpa.entity.TermConcept;
|
||||||
import ca.uhn.fhir.jpa.term.IRecordHandler;
|
import ca.uhn.fhir.jpa.term.IRecordHandler;
|
||||||
import org.hl7.fhir.r4.model.ConceptMap;
|
import org.hl7.fhir.r4.model.ConceptMap;
|
||||||
|
@ -66,7 +86,7 @@ abstract class BaseHandler implements IRecordHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void addConceptMapEntry(ConceptMapping theMapping) {
|
void addConceptMapEntry(ConceptMapping theMapping, String theCopyright) {
|
||||||
if (isBlank(theMapping.getSourceCode())) {
|
if (isBlank(theMapping.getSourceCode())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -86,6 +106,7 @@ abstract class BaseHandler implements IRecordHandler {
|
||||||
.addTelecom()
|
.addTelecom()
|
||||||
.setSystem(ContactPoint.ContactPointSystem.URL)
|
.setSystem(ContactPoint.ContactPointSystem.URL)
|
||||||
.setValue("https://loinc.org");
|
.setValue("https://loinc.org");
|
||||||
|
conceptMap.setCopyright(theCopyright);
|
||||||
myIdToConceptMaps.put(theMapping.getConceptMapId(), conceptMap);
|
myIdToConceptMaps.put(theMapping.getConceptMapId(), conceptMap);
|
||||||
myConceptMaps.add(conceptMap);
|
myConceptMaps.add(conceptMap);
|
||||||
} else {
|
} else {
|
||||||
|
@ -151,12 +172,13 @@ abstract class BaseHandler implements IRecordHandler {
|
||||||
vs.setId(theValueSetId);
|
vs.setId(theValueSetId);
|
||||||
vs.setName(theValueSetName);
|
vs.setName(theValueSetName);
|
||||||
vs.setStatus(Enumerations.PublicationStatus.ACTIVE);
|
vs.setStatus(Enumerations.PublicationStatus.ACTIVE);
|
||||||
vs.setPublisher("Regentrief Institute, Inc.");
|
vs.setPublisher("Regenstrief Institute, Inc.");
|
||||||
vs.addContact()
|
vs.addContact()
|
||||||
.setName("Regentrief Institute, Inc.")
|
.setName("Regenstrief Institute, Inc.")
|
||||||
.addTelecom()
|
.addTelecom()
|
||||||
.setSystem(ContactPoint.ContactPointSystem.URL)
|
.setSystem(ContactPoint.ContactPointSystem.URL)
|
||||||
.setValue("https://loinc.org");
|
.setValue("https://loinc.org");
|
||||||
|
vs.setCopyright("This content from LOINC® is copyright © 1995 Regenstrief Institute, Inc. and the LOINC Committee, and available at no cost under the license at https://loinc.org/license/");
|
||||||
myIdToValueSet.put(theValueSetId, vs);
|
myIdToValueSet.put(theValueSetId, vs);
|
||||||
myValueSets.add(vs);
|
myValueSets.add(vs);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.jpa.term.loinc;
|
package ca.uhn.fhir.jpa.term.loinc;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%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 ca.uhn.fhir.jpa.entity.TermConcept;
|
import ca.uhn.fhir.jpa.entity.TermConcept;
|
||||||
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
|
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
|
||||||
import ca.uhn.fhir.jpa.term.IRecordHandler;
|
import ca.uhn.fhir.jpa.term.IRecordHandler;
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.jpa.term.loinc;
|
package ca.uhn.fhir.jpa.term.loinc;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%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 ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
||||||
import ca.uhn.fhir.jpa.entity.TermConcept;
|
import ca.uhn.fhir.jpa.entity.TermConcept;
|
||||||
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
|
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.jpa.term.loinc;
|
package ca.uhn.fhir.jpa.term.loinc;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%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 ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
||||||
import ca.uhn.fhir.jpa.entity.TermConcept;
|
import ca.uhn.fhir.jpa.entity.TermConcept;
|
||||||
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
|
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.jpa.term.loinc;
|
package ca.uhn.fhir.jpa.term.loinc;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%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 ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
||||||
import ca.uhn.fhir.jpa.entity.TermConcept;
|
import ca.uhn.fhir.jpa.entity.TermConcept;
|
||||||
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
|
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
|
||||||
|
@ -15,8 +35,8 @@ import static org.apache.commons.lang3.StringUtils.trim;
|
||||||
|
|
||||||
public class LoincDocumentOntologyHandler extends BaseHandler implements IRecordHandler {
|
public class LoincDocumentOntologyHandler extends BaseHandler implements IRecordHandler {
|
||||||
|
|
||||||
public static final String DOCUMENT_ONTOLOGY_CODES_VS_ID = "DOCUMENT-ONTOLOGY-CODES-VS";
|
public static final String DOCUMENT_ONTOLOGY_CODES_VS_ID = "loinc-document-ontology";
|
||||||
public static final String DOCUMENT_ONTOLOGY_CODES_VS_URI = "http://loinc.org/document-ontology-codes";
|
public static final String DOCUMENT_ONTOLOGY_CODES_VS_URI = "http://loinc.org/vs/loinc-document-ontology";
|
||||||
public static final String DOCUMENT_ONTOLOGY_CODES_VS_NAME = "LOINC Document Ontology Codes";
|
public static final String DOCUMENT_ONTOLOGY_CODES_VS_NAME = "LOINC Document Ontology Codes";
|
||||||
private final Map<String, TermConcept> myCode2Concept;
|
private final Map<String, TermConcept> myCode2Concept;
|
||||||
private final TermCodeSystemVersion myCodeSystemVersion;
|
private final TermCodeSystemVersion myCodeSystemVersion;
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.jpa.term.loinc;
|
package ca.uhn.fhir.jpa.term.loinc;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%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 ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
||||||
import ca.uhn.fhir.jpa.entity.TermConcept;
|
import ca.uhn.fhir.jpa.entity.TermConcept;
|
||||||
import ca.uhn.fhir.jpa.term.IRecordHandler;
|
import ca.uhn.fhir.jpa.term.IRecordHandler;
|
||||||
|
@ -37,6 +57,13 @@ public class LoincHandler implements IRecordHandler {
|
||||||
TermConcept concept = new TermConcept(myCodeSystemVersion, code);
|
TermConcept concept = new TermConcept(myCodeSystemVersion, code);
|
||||||
concept.setDisplay(display);
|
concept.setDisplay(display);
|
||||||
|
|
||||||
|
if (!display.equalsIgnoreCase(shortName)) {
|
||||||
|
concept
|
||||||
|
.addDesignation()
|
||||||
|
.setUseDisplay("ShortName")
|
||||||
|
.setValue(shortName);
|
||||||
|
}
|
||||||
|
|
||||||
for (String nextPropertyName : myPropertyNames) {
|
for (String nextPropertyName : myPropertyNames) {
|
||||||
if (!theRecord.toMap().containsKey(nextPropertyName)) {
|
if (!theRecord.toMap().containsKey(nextPropertyName)) {
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.jpa.term.loinc;
|
package ca.uhn.fhir.jpa.term.loinc;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%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 ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
||||||
import ca.uhn.fhir.jpa.entity.TermConcept;
|
import ca.uhn.fhir.jpa.entity.TermConcept;
|
||||||
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink;
|
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink;
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.jpa.term.loinc;
|
package ca.uhn.fhir.jpa.term.loinc;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%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 ca.uhn.fhir.jpa.entity.TermConcept;
|
import ca.uhn.fhir.jpa.entity.TermConcept;
|
||||||
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
|
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
|
||||||
import ca.uhn.fhir.jpa.term.IRecordHandler;
|
import ca.uhn.fhir.jpa.term.IRecordHandler;
|
||||||
|
@ -18,6 +38,7 @@ public class LoincIeeeMedicalDeviceCodeHandler extends BaseHandler implements IR
|
||||||
public static final String LOINC_IEEE_CM_ID = "LOINC-IEEE-MEDICAL-DEVICE-CM";
|
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_URI = "http://loinc.org/fhir/loinc-ieee-device-code-mappings";
|
||||||
public static final String LOINC_IEEE_CM_NAME = "LOINC/IEEE Device Code Mappings";
|
public static final String LOINC_IEEE_CM_NAME = "LOINC/IEEE Device Code Mappings";
|
||||||
|
private static final String CM_COPYRIGHT = "This content from LOINC® is copyright © 1995 Regenstrief Institute, Inc. and the LOINC Committee, and available at no cost under the license at https://loinc.org/license/. The LOINC/IEEE Medical Device Code Mapping Table contains content from IEEE (http://ieee.org), copyright © 2017 IEEE.";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
|
@ -48,7 +69,8 @@ public class LoincIeeeMedicalDeviceCodeHandler extends BaseHandler implements IR
|
||||||
.setTargetCodeSystem(targetCodeSystemUri)
|
.setTargetCodeSystem(targetCodeSystemUri)
|
||||||
.setTargetCode(ieeeCode)
|
.setTargetCode(ieeeCode)
|
||||||
.setTargetDisplay(ieeeDisplayName)
|
.setTargetDisplay(ieeeDisplayName)
|
||||||
.setEquivalence(Enumerations.ConceptMapEquivalence.EQUAL));
|
.setEquivalence(Enumerations.ConceptMapEquivalence.EQUAL),
|
||||||
|
CM_COPYRIGHT);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.jpa.term.loinc;
|
package ca.uhn.fhir.jpa.term.loinc;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%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 ca.uhn.fhir.jpa.entity.TermConcept;
|
import ca.uhn.fhir.jpa.entity.TermConcept;
|
||||||
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
|
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
|
||||||
import ca.uhn.fhir.jpa.term.IRecordHandler;
|
import ca.uhn.fhir.jpa.term.IRecordHandler;
|
||||||
|
|
|
@ -1,20 +1,39 @@
|
||||||
package ca.uhn.fhir.jpa.term.loinc;
|
package ca.uhn.fhir.jpa.term.loinc;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%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 ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
||||||
import ca.uhn.fhir.jpa.entity.TermConcept;
|
import ca.uhn.fhir.jpa.entity.TermConcept;
|
||||||
import ca.uhn.fhir.jpa.term.IRecordHandler;
|
import ca.uhn.fhir.jpa.term.IRecordHandler;
|
||||||
import org.apache.commons.csv.CSVRecord;
|
import org.apache.commons.csv.CSVRecord;
|
||||||
import org.hl7.fhir.r4.model.ValueSet;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static org.apache.commons.lang3.StringUtils.trim;
|
import static org.apache.commons.lang3.StringUtils.trim;
|
||||||
|
|
||||||
public class LoincPartLinkHandler implements IRecordHandler {
|
public class LoincPartLinkHandler implements IRecordHandler {
|
||||||
|
|
||||||
|
private static final Logger ourLog = LoggerFactory.getLogger(LoincPartLinkHandler.class);
|
||||||
private final Map<String, TermConcept> myCode2Concept;
|
private final Map<String, TermConcept> myCode2Concept;
|
||||||
private final TermCodeSystemVersion myCodeSystemVersion;
|
private final TermCodeSystemVersion myCodeSystemVersion;
|
||||||
|
|
||||||
|
@ -33,11 +52,11 @@ public class LoincPartLinkHandler implements IRecordHandler {
|
||||||
TermConcept loincConcept = myCode2Concept.get(loincNumber);
|
TermConcept loincConcept = myCode2Concept.get(loincNumber);
|
||||||
TermConcept partConcept = myCode2Concept.get(partNumber);
|
TermConcept partConcept = myCode2Concept.get(partNumber);
|
||||||
|
|
||||||
if (loincConcept==null) {
|
if (loincConcept == null) {
|
||||||
ourLog.warn("No loinc code: {}", loincNumber);
|
ourLog.warn("No loinc code: {}", loincNumber);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (partConcept==null) {
|
if (partConcept == null) {
|
||||||
ourLog.warn("No part code: {}", partNumber);
|
ourLog.warn("No part code: {}", partNumber);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -45,5 +64,4 @@ public class LoincPartLinkHandler implements IRecordHandler {
|
||||||
// For now we're ignoring these
|
// For now we're ignoring these
|
||||||
|
|
||||||
}
|
}
|
||||||
private static final Logger ourLog = LoggerFactory.getLogger(LoincPartLinkHandler.class);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.jpa.term.loinc;
|
package ca.uhn.fhir.jpa.term.loinc;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%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 ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
||||||
import ca.uhn.fhir.jpa.entity.TermConcept;
|
import ca.uhn.fhir.jpa.entity.TermConcept;
|
||||||
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
|
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
|
||||||
|
@ -18,8 +38,9 @@ import static org.apache.commons.lang3.StringUtils.trim;
|
||||||
public class LoincPartRelatedCodeMappingHandler extends BaseHandler implements IRecordHandler {
|
public class LoincPartRelatedCodeMappingHandler extends BaseHandler implements IRecordHandler {
|
||||||
|
|
||||||
public static final String LOINC_PART_MAP_ID = "LOINC-PART-MAP";
|
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_URI = "http://loinc.org/cm/loinc-parts-to-snomed-ct";
|
||||||
public static final String LOINC_PART_MAP_NAME = "LOINC Part Map";
|
public static final String LOINC_PART_MAP_NAME = "LOINC Part Map";
|
||||||
|
private static final String CM_COPYRIGHT = "This content from LOINC® is copyright © 1995 Regenstrief Institute, Inc. and the LOINC Committee, and available at no cost under the license at https://loinc.org/license/. The LOINC Part File, LOINC/SNOMED CT Expression Association and Map Sets File, RELMA database and associated search index files include SNOMED Clinical Terms (SNOMED CT®) which is used by permission of the International Health Terminology Standards Development Organisation (IHTSDO) under license. All rights are reserved. SNOMED CT® was originally created by The College of American Pathologists. “SNOMED” and “SNOMED CT” are registered trademarks of the IHTSDO. 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. Under the terms of the Affiliate License, use of SNOMED CT in countries that are not IHTSDO Members is subject to reporting and fee payment obligations. However, IHTSDO agrees to waive the requirements to report and pay fees for use of SNOMED CT content included in the LOINC Part Mapping and LOINC Term Associations for purposes that support or enable more effective use of LOINC. 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.";
|
||||||
private final Map<String, TermConcept> myCode2Concept;
|
private final Map<String, TermConcept> myCode2Concept;
|
||||||
private final TermCodeSystemVersion myCodeSystemVersion;
|
private final TermCodeSystemVersion myCodeSystemVersion;
|
||||||
private final List<ConceptMap> myConceptMaps;
|
private final List<ConceptMap> myConceptMaps;
|
||||||
|
@ -76,7 +97,9 @@ public class LoincPartRelatedCodeMappingHandler extends BaseHandler implements I
|
||||||
.setTargetDisplay(extCodeDisplayName)
|
.setTargetDisplay(extCodeDisplayName)
|
||||||
.setTargetCodeSystemVersion(extCodeSystemVersion)
|
.setTargetCodeSystemVersion(extCodeSystemVersion)
|
||||||
.setEquivalence(equivalence)
|
.setEquivalence(equivalence)
|
||||||
.setCopyright(extCodeSystemCopyrightNotice));
|
.setCopyright(extCodeSystemCopyrightNotice),
|
||||||
|
CM_COPYRIGHT
|
||||||
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.jpa.term.loinc;
|
package ca.uhn.fhir.jpa.term.loinc;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%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 ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
||||||
import ca.uhn.fhir.jpa.entity.TermConcept;
|
import ca.uhn.fhir.jpa.entity.TermConcept;
|
||||||
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
|
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
|
||||||
|
@ -17,17 +37,27 @@ import static org.apache.commons.lang3.StringUtils.trim;
|
||||||
|
|
||||||
public class LoincRsnaPlaybookHandler extends BaseHandler 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_ID = "loinc-rsna-radiology-playbook";
|
||||||
public static final String RSNA_CODES_VS_URI = "http://loinc.org/rsna-codes";
|
public static final String RSNA_CODES_VS_URI = "http://loinc.org/vs/loinc-rsna-radiology-playbook";
|
||||||
public static final String RSNA_CODES_VS_NAME = "RSNA Playbook";
|
public static final String RSNA_CODES_VS_NAME = "LOINC/RSNA Radiology Playbook";
|
||||||
public static final String RID_MAPPING_CM_ID = "LOINC-TO-RID-CODES-CM";
|
public static final String RID_MAPPING_CM_ID = "LOINC-TO-RID-CODES-CM";
|
||||||
public static final String RID_MAPPING_CM_URI = "http://loinc.org/rid-codes";
|
public static final String RID_MAPPING_CM_URI = "http://loinc.org/rid-codes";
|
||||||
public static final String RID_MAPPING_CM_NAME = "RSNA Playbook RID Codes Mapping";
|
public static final String RID_MAPPING_CM_NAME = "RSNA Playbook RID Codes Mapping";
|
||||||
public static final String RID_CS_URI = "http://rid";
|
public static final String RID_CS_URI = "http://www.radlex.org";
|
||||||
public static final String RPID_MAPPING_CM_ID = "LOINC-TO-RPID-CODES-CM";
|
public static final String RPID_MAPPING_CM_ID = "LOINC-TO-RPID-CODES-CM";
|
||||||
public static final String RPID_MAPPING_CM_URI = "http://loinc.org/rpid-codes";
|
public static final String RPID_MAPPING_CM_URI = "http://loinc.org/rpid-codes";
|
||||||
public static final String RPID_MAPPING_CM_NAME = "RSNA Playbook RPID Codes Mapping";
|
public static final String RPID_MAPPING_CM_NAME = "RSNA Playbook RPID Codes Mapping";
|
||||||
public static final String RPID_CS_URI = "http://rpid";
|
/*
|
||||||
|
* About these being the same - Per Dan:
|
||||||
|
* We had some discussion about this, and both
|
||||||
|
* RIDs (RadLex clinical terms) and RPIDs (Radlex Playbook Ids)
|
||||||
|
* belong to the same "code system" since they will never collide.
|
||||||
|
* The codesystem uri is "http://www.radlex.org". FYI, that's
|
||||||
|
* now listed on the FHIR page:
|
||||||
|
* https://www.hl7.org/fhir/terminologies-systems.html
|
||||||
|
*/
|
||||||
|
public static final String RPID_CS_URI = RID_CS_URI;
|
||||||
|
private static final String CM_COPYRIGHT = "This content from LOINC® is copyright © 1995 Regenstrief Institute, Inc. and the LOINC Committee, and available at no cost under the license at https://loinc.org/license/. The LOINC/RSNA Radiology Playbook and the LOINC Part File contain content from RadLex® (http://rsna.org/RadLex.aspx), copyright © 2005-2017, The Radiological Society of North America, Inc., available at no cost under the license at http://www.rsna.org/uploadedFiles/RSNA/Content/Informatics/RadLex_License_Agreement_and_Terms_of_Use_V2_Final.pdf.";
|
||||||
private final Map<String, TermConcept> myCode2Concept;
|
private final Map<String, TermConcept> myCode2Concept;
|
||||||
private final TermCodeSystemVersion myCodeSystemVersion;
|
private final TermCodeSystemVersion myCodeSystemVersion;
|
||||||
private final Set<String> myPropertyNames;
|
private final Set<String> myPropertyNames;
|
||||||
|
@ -118,7 +148,8 @@ public class LoincRsnaPlaybookHandler extends BaseHandler implements IRecordHand
|
||||||
.setTargetCodeSystem(RID_CS_URI)
|
.setTargetCodeSystem(RID_CS_URI)
|
||||||
.setTargetCode(rid)
|
.setTargetCode(rid)
|
||||||
.setTargetDisplay(preferredName)
|
.setTargetDisplay(preferredName)
|
||||||
.setEquivalence(Enumerations.ConceptMapEquivalence.EQUAL));
|
.setEquivalence(Enumerations.ConceptMapEquivalence.EQUAL),
|
||||||
|
CM_COPYRIGHT);
|
||||||
}
|
}
|
||||||
|
|
||||||
// LOINC Term -> Radlex RPID code mappings
|
// LOINC Term -> Radlex RPID code mappings
|
||||||
|
@ -134,7 +165,8 @@ public class LoincRsnaPlaybookHandler extends BaseHandler implements IRecordHand
|
||||||
.setTargetCodeSystem(RPID_CS_URI)
|
.setTargetCodeSystem(RPID_CS_URI)
|
||||||
.setTargetCode(rpid)
|
.setTargetCode(rpid)
|
||||||
.setTargetDisplay(longName)
|
.setTargetDisplay(longName)
|
||||||
.setEquivalence(Enumerations.ConceptMapEquivalence.EQUAL));
|
.setEquivalence(Enumerations.ConceptMapEquivalence.EQUAL),
|
||||||
|
CM_COPYRIGHT);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.jpa.term.loinc;
|
package ca.uhn.fhir.jpa.term.loinc;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%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 ca.uhn.fhir.jpa.entity.TermConcept;
|
import ca.uhn.fhir.jpa.entity.TermConcept;
|
||||||
import org.hl7.fhir.r4.model.ConceptMap;
|
import org.hl7.fhir.r4.model.ConceptMap;
|
||||||
import org.hl7.fhir.r4.model.ValueSet;
|
import org.hl7.fhir.r4.model.ValueSet;
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.jpa.term.loinc;
|
package ca.uhn.fhir.jpa.term.loinc;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%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 ca.uhn.fhir.jpa.entity.TermConcept;
|
import ca.uhn.fhir.jpa.entity.TermConcept;
|
||||||
import org.hl7.fhir.r4.model.ConceptMap;
|
import org.hl7.fhir.r4.model.ConceptMap;
|
||||||
import org.hl7.fhir.r4.model.ValueSet;
|
import org.hl7.fhir.r4.model.ValueSet;
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.jpa.term.loinc;
|
package ca.uhn.fhir.jpa.term.loinc;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%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 ca.uhn.fhir.jpa.entity.TermConcept;
|
import ca.uhn.fhir.jpa.entity.TermConcept;
|
||||||
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
|
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
|
||||||
import ca.uhn.fhir.jpa.term.IRecordHandler;
|
import ca.uhn.fhir.jpa.term.IRecordHandler;
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.jpa.term.snomedct;
|
package ca.uhn.fhir.jpa.term.snomedct;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%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 ca.uhn.fhir.jpa.term.IRecordHandler;
|
import ca.uhn.fhir.jpa.term.IRecordHandler;
|
||||||
import org.apache.commons.csv.CSVRecord;
|
import org.apache.commons.csv.CSVRecord;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.jpa.term.snomedct;
|
package ca.uhn.fhir.jpa.term.snomedct;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%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 ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
||||||
import ca.uhn.fhir.jpa.entity.TermConcept;
|
import ca.uhn.fhir.jpa.entity.TermConcept;
|
||||||
import ca.uhn.fhir.jpa.term.IRecordHandler;
|
import ca.uhn.fhir.jpa.term.IRecordHandler;
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.jpa.term.snomedct;
|
package ca.uhn.fhir.jpa.term.snomedct;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%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 ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
||||||
import ca.uhn.fhir.jpa.entity.TermConcept;
|
import ca.uhn.fhir.jpa.entity.TermConcept;
|
||||||
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink;
|
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink;
|
||||||
|
|
|
@ -96,7 +96,7 @@ public class TestUtil {
|
||||||
assertThat(joinColumn.name(), null);
|
assertThat(joinColumn.name(), null);
|
||||||
ForeignKey fk = joinColumn.foreignKey();
|
ForeignKey fk = joinColumn.foreignKey();
|
||||||
Validate.notNull(fk);
|
Validate.notNull(fk);
|
||||||
Validate.isTrue(isNotBlank(fk.name()));
|
Validate.isTrue(isNotBlank(fk.name()), "Foreign key on " + ae.toString() + " has no name()");
|
||||||
Validate.isTrue(fk.name().startsWith("FK_"));
|
Validate.isTrue(fk.name().startsWith("FK_"));
|
||||||
assertThat(fk.name(), theNames);
|
assertThat(fk.name(), theNames);
|
||||||
}
|
}
|
||||||
|
|
|
@ -252,6 +252,7 @@ public abstract class BaseJpaTest {
|
||||||
public Void doInTransaction(TransactionStatus theStatus) {
|
public Void doInTransaction(TransactionStatus theStatus) {
|
||||||
entityManager.createQuery("UPDATE " + ResourceHistoryTable.class.getSimpleName() + " d SET d.myForcedId = null").executeUpdate();
|
entityManager.createQuery("UPDATE " + ResourceHistoryTable.class.getSimpleName() + " d SET d.myForcedId = null").executeUpdate();
|
||||||
entityManager.createQuery("UPDATE " + ResourceTable.class.getSimpleName() + " d SET d.myForcedId = null").executeUpdate();
|
entityManager.createQuery("UPDATE " + ResourceTable.class.getSimpleName() + " d SET d.myForcedId = null").executeUpdate();
|
||||||
|
entityManager.createQuery("UPDATE " + TermCodeSystem.class.getSimpleName() + " d SET d.myCurrentVersion = null").executeUpdate();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -279,6 +280,8 @@ public abstract class BaseJpaTest {
|
||||||
txTemplate.execute(new TransactionCallback<Void>() {
|
txTemplate.execute(new TransactionCallback<Void>() {
|
||||||
@Override
|
@Override
|
||||||
public Void doInTransaction(TransactionStatus theStatus) {
|
public Void doInTransaction(TransactionStatus theStatus) {
|
||||||
|
entityManager.createQuery("DELETE from " + TermConceptProperty.class.getSimpleName() + " d").executeUpdate();
|
||||||
|
entityManager.createQuery("DELETE from " + TermConceptDesignation.class.getSimpleName() + " d").executeUpdate();
|
||||||
entityManager.createQuery("DELETE from " + TermConcept.class.getSimpleName() + " d").executeUpdate();
|
entityManager.createQuery("DELETE from " + TermConcept.class.getSimpleName() + " d").executeUpdate();
|
||||||
for (TermCodeSystem next : entityManager.createQuery("SELECT c FROM " + TermCodeSystem.class.getName() + " c", TermCodeSystem.class).getResultList()) {
|
for (TermCodeSystem next : entityManager.createQuery("SELECT c FROM " + TermCodeSystem.class.getName() + " c", TermCodeSystem.class).getResultList()) {
|
||||||
next.setCurrentVersion(null);
|
next.setCurrentVersion(null);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package ca.uhn.fhir.jpa.dao.dstu2;
|
package ca.uhn.fhir.jpa.dao.dstu2;
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao;
|
import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao;
|
||||||
|
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
|
||||||
import ca.uhn.fhir.jpa.entity.TagTypeEnum;
|
import ca.uhn.fhir.jpa.entity.TagTypeEnum;
|
||||||
import ca.uhn.fhir.jpa.provider.SystemProviderDstu2Test;
|
import ca.uhn.fhir.jpa.provider.SystemProviderDstu2Test;
|
||||||
import ca.uhn.fhir.model.api.IResource;
|
import ca.uhn.fhir.model.api.IResource;
|
||||||
|
@ -18,11 +19,13 @@ import ca.uhn.fhir.model.dstu2.resource.Bundle.EntryResponse;
|
||||||
import ca.uhn.fhir.model.dstu2.valueset.BundleTypeEnum;
|
import ca.uhn.fhir.model.dstu2.valueset.BundleTypeEnum;
|
||||||
import ca.uhn.fhir.model.dstu2.valueset.HTTPVerbEnum;
|
import ca.uhn.fhir.model.dstu2.valueset.HTTPVerbEnum;
|
||||||
import ca.uhn.fhir.model.dstu2.valueset.IssueSeverityEnum;
|
import ca.uhn.fhir.model.dstu2.valueset.IssueSeverityEnum;
|
||||||
|
import ca.uhn.fhir.model.dstu2.valueset.ObservationStatusEnum;
|
||||||
import ca.uhn.fhir.model.primitive.IdDt;
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
import ca.uhn.fhir.model.primitive.UriDt;
|
import ca.uhn.fhir.model.primitive.UriDt;
|
||||||
import ca.uhn.fhir.rest.api.Constants;
|
import ca.uhn.fhir.rest.api.Constants;
|
||||||
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
||||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||||
|
import ca.uhn.fhir.rest.param.TokenParam;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.*;
|
import ca.uhn.fhir.rest.server.exceptions.*;
|
||||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
|
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
|
||||||
import ca.uhn.fhir.util.TestUtil;
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
|
@ -831,6 +834,213 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2SystemTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTransactionDoesntUpdateUnchangesResourceWithPlaceholderIds() {
|
||||||
|
Bundle output, input;
|
||||||
|
Bundle.EntryResponse respEntry;
|
||||||
|
IdType createdPatientId;
|
||||||
|
SearchParameterMap map;
|
||||||
|
IBundleProvider search;
|
||||||
|
|
||||||
|
input = new Bundle();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a transaction with a patient and an observation using
|
||||||
|
* placeholder IDs in them
|
||||||
|
*/
|
||||||
|
Patient pat = new Patient();
|
||||||
|
pat.setId(IdType.newRandomUuid());
|
||||||
|
pat.addIdentifier().setSystem("foo").setValue("bar");
|
||||||
|
input
|
||||||
|
.addEntry()
|
||||||
|
.setResource(pat)
|
||||||
|
.setFullUrl(pat.getId())
|
||||||
|
.getRequest()
|
||||||
|
.setMethod(HTTPVerbEnum.POST)
|
||||||
|
.setUrl("/Patient")
|
||||||
|
.setIfNoneExist("Patient?identifier=foo|bar");
|
||||||
|
Observation obs = new Observation();
|
||||||
|
obs.addIdentifier().setSystem("foo").setValue("dog");
|
||||||
|
obs.getSubject().setReference(pat.getId());
|
||||||
|
input
|
||||||
|
.addEntry()
|
||||||
|
.setResource(obs)
|
||||||
|
.getRequest()
|
||||||
|
.setMethod(HTTPVerbEnum.PUT)
|
||||||
|
.setUrl("/Observation?identifier=foo|dog");
|
||||||
|
output = mySystemDao.transaction(mySrd, input);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Both resrouces should be created and have version 1
|
||||||
|
*/
|
||||||
|
respEntry = output.getEntry().get(0).getResponse();
|
||||||
|
assertEquals("201 Created", respEntry.getStatus());
|
||||||
|
createdPatientId = new IdType(respEntry.getLocation());
|
||||||
|
assertEquals("Patient", createdPatientId.getResourceType());
|
||||||
|
assertEquals("1", createdPatientId.getVersionIdPart());
|
||||||
|
|
||||||
|
respEntry = output.getEntry().get(1).getResponse();
|
||||||
|
assertEquals("201 Created", respEntry.getStatus());
|
||||||
|
IdType createdObservationId = new IdType(respEntry.getLocation());
|
||||||
|
assertEquals("Observation", createdObservationId.getResourceType());
|
||||||
|
assertEquals("1", createdObservationId.getVersionIdPart());
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Searches for both resources should work and the reference
|
||||||
|
* should be substituted correctly
|
||||||
|
*/
|
||||||
|
// Patient
|
||||||
|
map = new SearchParameterMap();
|
||||||
|
map.setLoadSynchronous(true);
|
||||||
|
map.add(Patient.SP_IDENTIFIER, new TokenParam("foo", "bar"));
|
||||||
|
search = myPatientDao.search(map);
|
||||||
|
assertThat(toUnqualifiedVersionlessIdValues(search), contains(createdPatientId.toUnqualifiedVersionless().getValue()));
|
||||||
|
pat = (Patient) search.getResources(0, 1).get(0);
|
||||||
|
assertEquals("foo", pat.getIdentifierFirstRep().getSystem());
|
||||||
|
// Observation
|
||||||
|
map = new SearchParameterMap();
|
||||||
|
map.setLoadSynchronous(true);
|
||||||
|
map.add(Observation.SP_IDENTIFIER, new TokenParam("foo", "dog"));
|
||||||
|
search = myObservationDao.search(map);
|
||||||
|
assertThat(toUnqualifiedVersionlessIdValues(search), contains(createdObservationId.toUnqualifiedVersionless().getValue()));
|
||||||
|
obs = (Observation) search.getResources(0, 1).get(0);
|
||||||
|
assertEquals("foo", obs.getIdentifierFirstRep().getSystem());
|
||||||
|
assertEquals(createdPatientId.toUnqualifiedVersionless().getValue(), obs.getSubject().getReference().getValue());
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now run the same transaction, which should not make any changes this time
|
||||||
|
* around
|
||||||
|
*/
|
||||||
|
|
||||||
|
input = new Bundle();
|
||||||
|
pat = new Patient();
|
||||||
|
pat.setId(IdType.newRandomUuid());
|
||||||
|
pat.addIdentifier().setSystem("foo").setValue("bar");
|
||||||
|
input
|
||||||
|
.addEntry()
|
||||||
|
.setResource(pat)
|
||||||
|
.setFullUrl(pat.getId())
|
||||||
|
.getRequest()
|
||||||
|
.setMethod(HTTPVerbEnum.POST)
|
||||||
|
.setUrl("/Patient")
|
||||||
|
.setIfNoneExist("Patient?identifier=foo|bar");
|
||||||
|
obs = new Observation();
|
||||||
|
obs.addIdentifier().setSystem("foo").setValue("dog");
|
||||||
|
obs.getSubject().setReference(pat.getId());
|
||||||
|
input
|
||||||
|
.addEntry()
|
||||||
|
.setResource(obs)
|
||||||
|
.getRequest()
|
||||||
|
.setMethod(HTTPVerbEnum.PUT)
|
||||||
|
.setUrl("/Observation?identifier=foo|dog");
|
||||||
|
output = mySystemDao.transaction(mySrd, input);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Should still have version 1 of both resources
|
||||||
|
*/
|
||||||
|
respEntry = output.getEntry().get(0).getResponse();
|
||||||
|
assertEquals("200 OK", respEntry.getStatus());
|
||||||
|
createdObservationId = new IdType(respEntry.getLocation());
|
||||||
|
assertEquals("Patient", createdObservationId.getResourceType());
|
||||||
|
assertEquals("1", createdObservationId.getVersionIdPart());
|
||||||
|
|
||||||
|
respEntry = output.getEntry().get(1).getResponse();
|
||||||
|
assertEquals("200 OK", respEntry.getStatus());
|
||||||
|
createdObservationId = new IdType(respEntry.getLocation());
|
||||||
|
assertEquals("Observation", createdObservationId.getResourceType());
|
||||||
|
assertEquals("1", createdObservationId.getVersionIdPart());
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Searches for both resources should still work and the reference
|
||||||
|
* should be substituted correctly
|
||||||
|
*/
|
||||||
|
// Patient
|
||||||
|
map = new SearchParameterMap();
|
||||||
|
map.setLoadSynchronous(true);
|
||||||
|
map.add(Patient.SP_IDENTIFIER, new TokenParam("foo", "bar"));
|
||||||
|
search = myPatientDao.search(map);
|
||||||
|
assertThat(toUnqualifiedVersionlessIdValues(search), contains(createdPatientId.toUnqualifiedVersionless().getValue()));
|
||||||
|
pat = (Patient) search.getResources(0, 1).get(0);
|
||||||
|
assertEquals("foo", pat.getIdentifierFirstRep().getSystem());
|
||||||
|
// Observation
|
||||||
|
map = new SearchParameterMap();
|
||||||
|
map.setLoadSynchronous(true);
|
||||||
|
map.add(Observation.SP_IDENTIFIER, new TokenParam("foo", "dog"));
|
||||||
|
search = myObservationDao.search(map);
|
||||||
|
assertThat(toUnqualifiedVersionlessIdValues(search), contains(createdObservationId.toUnqualifiedVersionless().getValue()));
|
||||||
|
obs = (Observation) search.getResources(0, 1).get(0);
|
||||||
|
assertEquals("foo", obs.getIdentifierFirstRep().getSystem());
|
||||||
|
assertEquals(createdPatientId.toUnqualifiedVersionless().getValue(), obs.getSubject().getReference().getValue());
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now run the transaction, but this time with an actual
|
||||||
|
* change to the Observation
|
||||||
|
*/
|
||||||
|
|
||||||
|
input = new Bundle();
|
||||||
|
pat = new Patient();
|
||||||
|
pat.setId(IdType.newRandomUuid());
|
||||||
|
pat.addIdentifier().setSystem("foo").setValue("bar");
|
||||||
|
input
|
||||||
|
.addEntry()
|
||||||
|
.setResource(pat)
|
||||||
|
.setFullUrl(pat.getId())
|
||||||
|
.getRequest()
|
||||||
|
.setMethod(HTTPVerbEnum.POST)
|
||||||
|
.setUrl("/Patient")
|
||||||
|
.setIfNoneExist("Patient?identifier=foo|bar");
|
||||||
|
obs = new Observation();
|
||||||
|
obs.addIdentifier().setSystem("foo").setValue("dog");
|
||||||
|
obs.setStatus(ObservationStatusEnum.FINAL);
|
||||||
|
obs.getSubject().setReference(pat.getId());
|
||||||
|
input
|
||||||
|
.addEntry()
|
||||||
|
.setResource(obs)
|
||||||
|
.getRequest()
|
||||||
|
.setMethod(HTTPVerbEnum.PUT)
|
||||||
|
.setUrl("/Observation?identifier=foo|dog");
|
||||||
|
output = mySystemDao.transaction(mySrd, input);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Observation should now be version 2
|
||||||
|
*/
|
||||||
|
respEntry = output.getEntry().get(0).getResponse();
|
||||||
|
assertEquals("200 OK", respEntry.getStatus());
|
||||||
|
createdObservationId = new IdType(respEntry.getLocation());
|
||||||
|
assertEquals("Patient", createdObservationId.getResourceType());
|
||||||
|
assertEquals("1", createdObservationId.getVersionIdPart());
|
||||||
|
|
||||||
|
respEntry = output.getEntry().get(1).getResponse();
|
||||||
|
assertEquals("200 OK", respEntry.getStatus());
|
||||||
|
createdObservationId = new IdType(respEntry.getLocation());
|
||||||
|
assertEquals("Observation", createdObservationId.getResourceType());
|
||||||
|
assertEquals("2", createdObservationId.getVersionIdPart());
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Searches for both resources should still work and the reference
|
||||||
|
* should be substituted correctly
|
||||||
|
*/
|
||||||
|
// Patient
|
||||||
|
map = new SearchParameterMap();
|
||||||
|
map.setLoadSynchronous(true);
|
||||||
|
map.add(Patient.SP_IDENTIFIER, new TokenParam("foo", "bar"));
|
||||||
|
search = myPatientDao.search(map);
|
||||||
|
assertThat(toUnqualifiedVersionlessIdValues(search), contains(createdPatientId.toUnqualifiedVersionless().getValue()));
|
||||||
|
pat = (Patient) search.getResources(0, 1).get(0);
|
||||||
|
assertEquals("foo", pat.getIdentifierFirstRep().getSystem());
|
||||||
|
// Observation
|
||||||
|
map = new SearchParameterMap();
|
||||||
|
map.setLoadSynchronous(true);
|
||||||
|
map.add(Observation.SP_IDENTIFIER, new TokenParam("foo", "dog"));
|
||||||
|
search = myObservationDao.search(map);
|
||||||
|
assertThat(toUnqualifiedVersionlessIdValues(search), contains(createdObservationId.toUnqualifiedVersionless().getValue()));
|
||||||
|
obs = (Observation) search.getResources(0, 1).get(0);
|
||||||
|
assertEquals("foo", obs.getIdentifierFirstRep().getSystem());
|
||||||
|
assertEquals(createdPatientId.toUnqualifiedVersionless().getValue(), obs.getSubject().getReference().getValue());
|
||||||
|
assertEquals(ObservationStatusEnum.FINAL.getCode(), obs.getStatus());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Test(expected = InvalidRequestException.class)
|
@Test(expected = InvalidRequestException.class)
|
||||||
public void testTransactionFailsWithDuplicateIds() {
|
public void testTransactionFailsWithDuplicateIds() {
|
||||||
Bundle request = new Bundle();
|
Bundle request = new Bundle();
|
||||||
|
@ -1193,62 +1403,6 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2SystemTest {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testTransactionUpdateResourceNewVersionCreatedWhenDataChanges() {
|
|
||||||
|
|
||||||
Bundle request = new Bundle();
|
|
||||||
String patientId = "Patient/IShouldUpdate";
|
|
||||||
Patient p = new Patient();
|
|
||||||
p.addName().addFamily("Hello");
|
|
||||||
p.setId(patientId);
|
|
||||||
request.addEntry().setResource(p).getRequest().setMethod(HTTPVerbEnum.PUT).setUrl(patientId);
|
|
||||||
|
|
||||||
Bundle initialBundleResponse = mySystemDao.transaction(mySrd, request);
|
|
||||||
assertEquals(1, initialBundleResponse.getEntry().size());
|
|
||||||
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(initialBundleResponse));
|
|
||||||
|
|
||||||
Entry initialBundleResponseEntry = initialBundleResponse.getEntry().get(0);
|
|
||||||
assertEquals("201 Created", initialBundleResponseEntry.getResponse().getStatus());
|
|
||||||
assertThat(initialBundleResponseEntry.getResponse().getEtag(), is(equalTo("1")));
|
|
||||||
|
|
||||||
p.addName().addFamily("AnotherName");
|
|
||||||
|
|
||||||
Bundle secondBundleResponse = mySystemDao.transaction(mySrd, request);
|
|
||||||
assertEquals(1, secondBundleResponse.getEntry().size());
|
|
||||||
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(secondBundleResponse));
|
|
||||||
|
|
||||||
Entry secondBundleResponseEntry = secondBundleResponse.getEntry().get(0);
|
|
||||||
assertEquals("200 OK", secondBundleResponseEntry.getResponse().getStatus());
|
|
||||||
assertThat(secondBundleResponseEntry.getResponse().getEtag(), is(equalTo("2")));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testTransactionUpdateResourceNewVersionNotCreatedWhenDataNotChanged() {
|
|
||||||
|
|
||||||
Bundle request = new Bundle();
|
|
||||||
String patientId = "Patient/IShouldNotUpdate";
|
|
||||||
Patient p = new Patient();
|
|
||||||
p.addName().addFamily("Hello");
|
|
||||||
p.setId(patientId);
|
|
||||||
request.addEntry().setResource(p).getRequest().setMethod(HTTPVerbEnum.PUT).setUrl(patientId);
|
|
||||||
|
|
||||||
Bundle initialBundleResponse = mySystemDao.transaction(mySrd, request);
|
|
||||||
assertEquals(1, initialBundleResponse.getEntry().size());
|
|
||||||
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(initialBundleResponse));
|
|
||||||
|
|
||||||
Entry initialBundleResponseEntry = initialBundleResponse.getEntry().get(0);
|
|
||||||
assertEquals("201 Created", initialBundleResponseEntry.getResponse().getStatus());
|
|
||||||
assertThat(initialBundleResponseEntry.getResponse().getEtag(), is(equalTo("1")));
|
|
||||||
|
|
||||||
Bundle secondBundleResponse = mySystemDao.transaction(mySrd, request);
|
|
||||||
assertEquals(1, secondBundleResponse.getEntry().size());
|
|
||||||
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(secondBundleResponse));
|
|
||||||
|
|
||||||
Entry secondBundleResponseEntry = secondBundleResponse.getEntry().get(0);
|
|
||||||
assertEquals("200 OK", secondBundleResponseEntry.getResponse().getStatus());
|
|
||||||
assertThat(secondBundleResponseEntry.getResponse().getEtag(), is(equalTo("1")));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTransactionUpdateMatchUrlWithTwoMatch() {
|
public void testTransactionUpdateMatchUrlWithTwoMatch() {
|
||||||
String methodName = "testTransactionUpdateMatchUrlWithTwoMatch";
|
String methodName = "testTransactionUpdateMatchUrlWithTwoMatch";
|
||||||
|
@ -1362,6 +1516,62 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2SystemTest {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTransactionUpdateResourceNewVersionCreatedWhenDataChanges() {
|
||||||
|
|
||||||
|
Bundle request = new Bundle();
|
||||||
|
String patientId = "Patient/IShouldUpdate";
|
||||||
|
Patient p = new Patient();
|
||||||
|
p.addName().addFamily("Hello");
|
||||||
|
p.setId(patientId);
|
||||||
|
request.addEntry().setResource(p).getRequest().setMethod(HTTPVerbEnum.PUT).setUrl(patientId);
|
||||||
|
|
||||||
|
Bundle initialBundleResponse = mySystemDao.transaction(mySrd, request);
|
||||||
|
assertEquals(1, initialBundleResponse.getEntry().size());
|
||||||
|
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(initialBundleResponse));
|
||||||
|
|
||||||
|
Entry initialBundleResponseEntry = initialBundleResponse.getEntry().get(0);
|
||||||
|
assertEquals("201 Created", initialBundleResponseEntry.getResponse().getStatus());
|
||||||
|
assertThat(initialBundleResponseEntry.getResponse().getEtag(), is(equalTo("1")));
|
||||||
|
|
||||||
|
p.addName().addFamily("AnotherName");
|
||||||
|
|
||||||
|
Bundle secondBundleResponse = mySystemDao.transaction(mySrd, request);
|
||||||
|
assertEquals(1, secondBundleResponse.getEntry().size());
|
||||||
|
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(secondBundleResponse));
|
||||||
|
|
||||||
|
Entry secondBundleResponseEntry = secondBundleResponse.getEntry().get(0);
|
||||||
|
assertEquals("200 OK", secondBundleResponseEntry.getResponse().getStatus());
|
||||||
|
assertThat(secondBundleResponseEntry.getResponse().getEtag(), is(equalTo("2")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTransactionUpdateResourceNewVersionNotCreatedWhenDataNotChanged() {
|
||||||
|
|
||||||
|
Bundle request = new Bundle();
|
||||||
|
String patientId = "Patient/IShouldNotUpdate";
|
||||||
|
Patient p = new Patient();
|
||||||
|
p.addName().addFamily("Hello");
|
||||||
|
p.setId(patientId);
|
||||||
|
request.addEntry().setResource(p).getRequest().setMethod(HTTPVerbEnum.PUT).setUrl(patientId);
|
||||||
|
|
||||||
|
Bundle initialBundleResponse = mySystemDao.transaction(mySrd, request);
|
||||||
|
assertEquals(1, initialBundleResponse.getEntry().size());
|
||||||
|
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(initialBundleResponse));
|
||||||
|
|
||||||
|
Entry initialBundleResponseEntry = initialBundleResponse.getEntry().get(0);
|
||||||
|
assertEquals("201 Created", initialBundleResponseEntry.getResponse().getStatus());
|
||||||
|
assertThat(initialBundleResponseEntry.getResponse().getEtag(), is(equalTo("1")));
|
||||||
|
|
||||||
|
Bundle secondBundleResponse = mySystemDao.transaction(mySrd, request);
|
||||||
|
assertEquals(1, secondBundleResponse.getEntry().size());
|
||||||
|
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(secondBundleResponse));
|
||||||
|
|
||||||
|
Entry secondBundleResponseEntry = secondBundleResponse.getEntry().get(0);
|
||||||
|
assertEquals("200 OK", secondBundleResponseEntry.getResponse().getStatus());
|
||||||
|
assertThat(secondBundleResponseEntry.getResponse().getEtag(), is(equalTo("1")));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTransactionWhichFailsPersistsNothing() {
|
public void testTransactionWhichFailsPersistsNothing() {
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ import ca.uhn.fhir.rest.api.Constants;
|
||||||
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
||||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||||
import ca.uhn.fhir.rest.param.ReferenceParam;
|
import ca.uhn.fhir.rest.param.ReferenceParam;
|
||||||
|
import ca.uhn.fhir.rest.param.TokenParam;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.*;
|
import ca.uhn.fhir.rest.server.exceptions.*;
|
||||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
|
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
|
||||||
import ca.uhn.fhir.util.TestUtil;
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
|
@ -1439,6 +1440,213 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
|
||||||
assertTrue(p.getGeneralPractitionerFirstRep().getReferenceElement().isIdPartValidLong());
|
assertTrue(p.getGeneralPractitionerFirstRep().getReferenceElement().isIdPartValidLong());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTransactionDoesntUpdateUnchangesResourceWithPlaceholderIds() {
|
||||||
|
Bundle output, input;
|
||||||
|
BundleEntryResponseComponent respEntry;
|
||||||
|
IdType createdPatientId;
|
||||||
|
SearchParameterMap map;
|
||||||
|
IBundleProvider search;
|
||||||
|
|
||||||
|
input = new Bundle();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a transaction with a patient and an observation using
|
||||||
|
* placeholder IDs in them
|
||||||
|
*/
|
||||||
|
Patient pat = new Patient();
|
||||||
|
pat.setId(IdType.newRandomUuid());
|
||||||
|
pat.addIdentifier().setSystem("foo").setValue("bar");
|
||||||
|
input
|
||||||
|
.addEntry()
|
||||||
|
.setResource(pat)
|
||||||
|
.setFullUrl(pat.getId())
|
||||||
|
.getRequest()
|
||||||
|
.setMethod(HTTPVerb.POST)
|
||||||
|
.setUrl("/Patient")
|
||||||
|
.setIfNoneExist("Patient?identifier=foo|bar");
|
||||||
|
Observation obs = new Observation();
|
||||||
|
obs.addIdentifier().setSystem("foo").setValue("dog");
|
||||||
|
obs.getSubject().setReference(pat.getId());
|
||||||
|
input
|
||||||
|
.addEntry()
|
||||||
|
.setResource(obs)
|
||||||
|
.getRequest()
|
||||||
|
.setMethod(HTTPVerb.PUT)
|
||||||
|
.setUrl("/Observation?identifier=foo|dog");
|
||||||
|
output = mySystemDao.transaction(mySrd, input);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Both resrouces should be created and have version 1
|
||||||
|
*/
|
||||||
|
respEntry = output.getEntry().get(0).getResponse();
|
||||||
|
assertEquals("201 Created", respEntry.getStatus());
|
||||||
|
createdPatientId = new IdType(respEntry.getLocation());
|
||||||
|
assertEquals("Patient", createdPatientId.getResourceType());
|
||||||
|
assertEquals("1", createdPatientId.getVersionIdPart());
|
||||||
|
|
||||||
|
respEntry = output.getEntry().get(1).getResponse();
|
||||||
|
assertEquals("201 Created", respEntry.getStatus());
|
||||||
|
IdType createdObservationId = new IdType(respEntry.getLocation());
|
||||||
|
assertEquals("Observation", createdObservationId.getResourceType());
|
||||||
|
assertEquals("1", createdObservationId.getVersionIdPart());
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Searches for both resources should work and the reference
|
||||||
|
* should be substituted correctly
|
||||||
|
*/
|
||||||
|
// Patient
|
||||||
|
map = new SearchParameterMap();
|
||||||
|
map.setLoadSynchronous(true);
|
||||||
|
map.add(Patient.SP_IDENTIFIER, new TokenParam("foo", "bar"));
|
||||||
|
search = myPatientDao.search(map);
|
||||||
|
assertThat(toUnqualifiedVersionlessIdValues(search), contains(createdPatientId.toUnqualifiedVersionless().getValue()));
|
||||||
|
pat = (Patient) search.getResources(0, 1).get(0);
|
||||||
|
assertEquals("foo", pat.getIdentifierFirstRep().getSystem());
|
||||||
|
// Observation
|
||||||
|
map = new SearchParameterMap();
|
||||||
|
map.setLoadSynchronous(true);
|
||||||
|
map.add(Observation.SP_IDENTIFIER, new TokenParam("foo", "dog"));
|
||||||
|
search = myObservationDao.search(map);
|
||||||
|
assertThat(toUnqualifiedVersionlessIdValues(search), contains(createdObservationId.toUnqualifiedVersionless().getValue()));
|
||||||
|
obs = (Observation) search.getResources(0, 1).get(0);
|
||||||
|
assertEquals("foo", obs.getIdentifierFirstRep().getSystem());
|
||||||
|
assertEquals(createdPatientId.toUnqualifiedVersionless().getValue(), obs.getSubject().getReference());
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now run the same transaction, which should not make any changes this time
|
||||||
|
* around
|
||||||
|
*/
|
||||||
|
|
||||||
|
input = new Bundle();
|
||||||
|
pat = new Patient();
|
||||||
|
pat.setId(IdType.newRandomUuid());
|
||||||
|
pat.addIdentifier().setSystem("foo").setValue("bar");
|
||||||
|
input
|
||||||
|
.addEntry()
|
||||||
|
.setResource(pat)
|
||||||
|
.setFullUrl(pat.getId())
|
||||||
|
.getRequest()
|
||||||
|
.setMethod(HTTPVerb.POST)
|
||||||
|
.setUrl("/Patient")
|
||||||
|
.setIfNoneExist("Patient?identifier=foo|bar");
|
||||||
|
obs = new Observation();
|
||||||
|
obs.addIdentifier().setSystem("foo").setValue("dog");
|
||||||
|
obs.getSubject().setReference(pat.getId());
|
||||||
|
input
|
||||||
|
.addEntry()
|
||||||
|
.setResource(obs)
|
||||||
|
.getRequest()
|
||||||
|
.setMethod(HTTPVerb.PUT)
|
||||||
|
.setUrl("/Observation?identifier=foo|dog");
|
||||||
|
output = mySystemDao.transaction(mySrd, input);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Should still have version 1 of both resources
|
||||||
|
*/
|
||||||
|
respEntry = output.getEntry().get(0).getResponse();
|
||||||
|
assertEquals("200 OK", respEntry.getStatus());
|
||||||
|
createdObservationId = new IdType(respEntry.getLocation());
|
||||||
|
assertEquals("Patient", createdObservationId.getResourceType());
|
||||||
|
assertEquals("1", createdObservationId.getVersionIdPart());
|
||||||
|
|
||||||
|
respEntry = output.getEntry().get(1).getResponse();
|
||||||
|
assertEquals("200 OK", respEntry.getStatus());
|
||||||
|
createdObservationId = new IdType(respEntry.getLocation());
|
||||||
|
assertEquals("Observation", createdObservationId.getResourceType());
|
||||||
|
assertEquals("1", createdObservationId.getVersionIdPart());
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Searches for both resources should still work and the reference
|
||||||
|
* should be substituted correctly
|
||||||
|
*/
|
||||||
|
// Patient
|
||||||
|
map = new SearchParameterMap();
|
||||||
|
map.setLoadSynchronous(true);
|
||||||
|
map.add(Patient.SP_IDENTIFIER, new TokenParam("foo", "bar"));
|
||||||
|
search = myPatientDao.search(map);
|
||||||
|
assertThat(toUnqualifiedVersionlessIdValues(search), contains(createdPatientId.toUnqualifiedVersionless().getValue()));
|
||||||
|
pat = (Patient) search.getResources(0, 1).get(0);
|
||||||
|
assertEquals("foo", pat.getIdentifierFirstRep().getSystem());
|
||||||
|
// Observation
|
||||||
|
map = new SearchParameterMap();
|
||||||
|
map.setLoadSynchronous(true);
|
||||||
|
map.add(Observation.SP_IDENTIFIER, new TokenParam("foo", "dog"));
|
||||||
|
search = myObservationDao.search(map);
|
||||||
|
assertThat(toUnqualifiedVersionlessIdValues(search), contains(createdObservationId.toUnqualifiedVersionless().getValue()));
|
||||||
|
obs = (Observation) search.getResources(0, 1).get(0);
|
||||||
|
assertEquals("foo", obs.getIdentifierFirstRep().getSystem());
|
||||||
|
assertEquals(createdPatientId.toUnqualifiedVersionless().getValue(), obs.getSubject().getReference());
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now run the transaction, but this time with an actual
|
||||||
|
* change to the Observation
|
||||||
|
*/
|
||||||
|
|
||||||
|
input = new Bundle();
|
||||||
|
pat = new Patient();
|
||||||
|
pat.setId(IdType.newRandomUuid());
|
||||||
|
pat.addIdentifier().setSystem("foo").setValue("bar");
|
||||||
|
input
|
||||||
|
.addEntry()
|
||||||
|
.setResource(pat)
|
||||||
|
.setFullUrl(pat.getId())
|
||||||
|
.getRequest()
|
||||||
|
.setMethod(HTTPVerb.POST)
|
||||||
|
.setUrl("/Patient")
|
||||||
|
.setIfNoneExist("Patient?identifier=foo|bar");
|
||||||
|
obs = new Observation();
|
||||||
|
obs.addIdentifier().setSystem("foo").setValue("dog");
|
||||||
|
obs.setStatus(ObservationStatus.FINAL);
|
||||||
|
obs.getSubject().setReference(pat.getId());
|
||||||
|
input
|
||||||
|
.addEntry()
|
||||||
|
.setResource(obs)
|
||||||
|
.getRequest()
|
||||||
|
.setMethod(HTTPVerb.PUT)
|
||||||
|
.setUrl("/Observation?identifier=foo|dog");
|
||||||
|
output = mySystemDao.transaction(mySrd, input);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Observation should now be version 2
|
||||||
|
*/
|
||||||
|
respEntry = output.getEntry().get(0).getResponse();
|
||||||
|
assertEquals("200 OK", respEntry.getStatus());
|
||||||
|
createdObservationId = new IdType(respEntry.getLocation());
|
||||||
|
assertEquals("Patient", createdObservationId.getResourceType());
|
||||||
|
assertEquals("1", createdObservationId.getVersionIdPart());
|
||||||
|
|
||||||
|
respEntry = output.getEntry().get(1).getResponse();
|
||||||
|
assertEquals("200 OK", respEntry.getStatus());
|
||||||
|
createdObservationId = new IdType(respEntry.getLocation());
|
||||||
|
assertEquals("Observation", createdObservationId.getResourceType());
|
||||||
|
assertEquals("2", createdObservationId.getVersionIdPart());
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Searches for both resources should still work and the reference
|
||||||
|
* should be substituted correctly
|
||||||
|
*/
|
||||||
|
// Patient
|
||||||
|
map = new SearchParameterMap();
|
||||||
|
map.setLoadSynchronous(true);
|
||||||
|
map.add(Patient.SP_IDENTIFIER, new TokenParam("foo", "bar"));
|
||||||
|
search = myPatientDao.search(map);
|
||||||
|
assertThat(toUnqualifiedVersionlessIdValues(search), contains(createdPatientId.toUnqualifiedVersionless().getValue()));
|
||||||
|
pat = (Patient) search.getResources(0, 1).get(0);
|
||||||
|
assertEquals("foo", pat.getIdentifierFirstRep().getSystem());
|
||||||
|
// Observation
|
||||||
|
map = new SearchParameterMap();
|
||||||
|
map.setLoadSynchronous(true);
|
||||||
|
map.add(Observation.SP_IDENTIFIER, new TokenParam("foo", "dog"));
|
||||||
|
search = myObservationDao.search(map);
|
||||||
|
assertThat(toUnqualifiedVersionlessIdValues(search), contains(createdObservationId.toUnqualifiedVersionless().getValue()));
|
||||||
|
obs = (Observation) search.getResources(0, 1).get(0);
|
||||||
|
assertEquals("foo", obs.getIdentifierFirstRep().getSystem());
|
||||||
|
assertEquals(createdPatientId.toUnqualifiedVersionless().getValue(), obs.getSubject().getReference());
|
||||||
|
assertEquals(ObservationStatus.FINAL, obs.getStatus());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTransactionDoubleConditionalCreateOnlyCreatesOne() {
|
public void testTransactionDoubleConditionalCreateOnlyCreatesOne() {
|
||||||
Bundle inputBundle = new Bundle();
|
Bundle inputBundle = new Bundle();
|
||||||
|
|
|
@ -11,6 +11,7 @@ import ca.uhn.fhir.rest.api.Constants;
|
||||||
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
||||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||||
import ca.uhn.fhir.rest.param.ReferenceParam;
|
import ca.uhn.fhir.rest.param.ReferenceParam;
|
||||||
|
import ca.uhn.fhir.rest.param.TokenParam;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.*;
|
import ca.uhn.fhir.rest.server.exceptions.*;
|
||||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
|
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
|
||||||
import ca.uhn.fhir.util.TestUtil;
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
|
@ -1515,13 +1516,19 @@ public class FhirSystemDaoR4Test extends BaseJpaR4SystemTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTransactionDoesntDoubleCreate() {
|
public void testTransactionDoesntUpdateUnchangesResourceWithPlaceholderIds() {
|
||||||
Bundle output, input;
|
Bundle output, input;
|
||||||
BundleEntryResponseComponent respEntry;
|
BundleEntryResponseComponent respEntry;
|
||||||
IdType createdId;
|
IdType createdPatientId;
|
||||||
|
SearchParameterMap map;
|
||||||
|
IBundleProvider search;
|
||||||
|
|
||||||
input = new Bundle();
|
input = new Bundle();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a transaction with a patient and an observation using
|
||||||
|
* placeholder IDs in them
|
||||||
|
*/
|
||||||
Patient pat = new Patient();
|
Patient pat = new Patient();
|
||||||
pat.setId(IdType.newRandomUuid());
|
pat.setId(IdType.newRandomUuid());
|
||||||
pat.addIdentifier().setSystem("foo").setValue("bar");
|
pat.addIdentifier().setSystem("foo").setValue("bar");
|
||||||
|
@ -1542,24 +1549,51 @@ public class FhirSystemDaoR4Test extends BaseJpaR4SystemTest {
|
||||||
.getRequest()
|
.getRequest()
|
||||||
.setMethod(HTTPVerb.PUT)
|
.setMethod(HTTPVerb.PUT)
|
||||||
.setUrl("/Observation?identifier=foo|dog");
|
.setUrl("/Observation?identifier=foo|dog");
|
||||||
|
|
||||||
output = mySystemDao.transaction(mySrd, input);
|
output = mySystemDao.transaction(mySrd, input);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Both resrouces should be created and have version 1
|
||||||
|
*/
|
||||||
respEntry = output.getEntry().get(0).getResponse();
|
respEntry = output.getEntry().get(0).getResponse();
|
||||||
assertEquals("201 Created", respEntry.getStatus());
|
assertEquals("201 Created", respEntry.getStatus());
|
||||||
createdId = new IdType(respEntry.getLocation());
|
createdPatientId = new IdType(respEntry.getLocation());
|
||||||
assertEquals("Patient", createdId.getResourceType());
|
assertEquals("Patient", createdPatientId.getResourceType());
|
||||||
assertEquals("1", createdId.getVersionIdPart());
|
assertEquals("1", createdPatientId.getVersionIdPart());
|
||||||
|
|
||||||
respEntry = output.getEntry().get(1).getResponse();
|
respEntry = output.getEntry().get(1).getResponse();
|
||||||
assertEquals("201 Created", respEntry.getStatus());
|
assertEquals("201 Created", respEntry.getStatus());
|
||||||
createdId = new IdType(respEntry.getLocation());
|
IdType createdObservationId = new IdType(respEntry.getLocation());
|
||||||
assertEquals("Observation", createdId.getResourceType());
|
assertEquals("Observation", createdObservationId.getResourceType());
|
||||||
assertEquals("1", createdId.getVersionIdPart());
|
assertEquals("1", createdObservationId.getVersionIdPart());
|
||||||
|
|
||||||
// Same bundle again
|
/*
|
||||||
|
* Searches for both resources should work and the reference
|
||||||
|
* should be substituted correctly
|
||||||
|
*/
|
||||||
|
// Patient
|
||||||
|
map = new SearchParameterMap();
|
||||||
|
map.setLoadSynchronous(true);
|
||||||
|
map.add(Patient.SP_IDENTIFIER, new TokenParam("foo", "bar"));
|
||||||
|
search = myPatientDao.search(map);
|
||||||
|
assertThat(toUnqualifiedVersionlessIdValues(search), contains(createdPatientId.toUnqualifiedVersionless().getValue()));
|
||||||
|
pat = (Patient) search.getResources(0,1).get(0);
|
||||||
|
assertEquals("foo", pat.getIdentifierFirstRep().getSystem());
|
||||||
|
// Observation
|
||||||
|
map = new SearchParameterMap();
|
||||||
|
map.setLoadSynchronous(true);
|
||||||
|
map.add(Observation.SP_IDENTIFIER, new TokenParam("foo", "dog"));
|
||||||
|
search = myObservationDao.search(map);
|
||||||
|
assertThat(toUnqualifiedVersionlessIdValues(search), contains(createdObservationId.toUnqualifiedVersionless().getValue()));
|
||||||
|
obs = (Observation) search.getResources(0,1).get(0);
|
||||||
|
assertEquals("foo", obs.getIdentifierFirstRep().getSystem());
|
||||||
|
assertEquals(createdPatientId.toUnqualifiedVersionless().getValue(), obs.getSubject().getReference());
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now run the same transaction, which should not make any changes this time
|
||||||
|
* around
|
||||||
|
*/
|
||||||
|
|
||||||
input = new Bundle();
|
input = new Bundle();
|
||||||
|
|
||||||
pat = new Patient();
|
pat = new Patient();
|
||||||
pat.setId(IdType.newRandomUuid());
|
pat.setId(IdType.newRandomUuid());
|
||||||
pat.addIdentifier().setSystem("foo").setValue("bar");
|
pat.addIdentifier().setSystem("foo").setValue("bar");
|
||||||
|
@ -1580,20 +1614,111 @@ public class FhirSystemDaoR4Test extends BaseJpaR4SystemTest {
|
||||||
.getRequest()
|
.getRequest()
|
||||||
.setMethod(HTTPVerb.PUT)
|
.setMethod(HTTPVerb.PUT)
|
||||||
.setUrl("/Observation?identifier=foo|dog");
|
.setUrl("/Observation?identifier=foo|dog");
|
||||||
|
|
||||||
|
|
||||||
output = mySystemDao.transaction(mySrd, input);
|
output = mySystemDao.transaction(mySrd, input);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Should still have version 1 of both resources
|
||||||
|
*/
|
||||||
respEntry = output.getEntry().get(0).getResponse();
|
respEntry = output.getEntry().get(0).getResponse();
|
||||||
assertEquals("200 OK", respEntry.getStatus());
|
assertEquals("200 OK", respEntry.getStatus());
|
||||||
createdId = new IdType(respEntry.getLocation());
|
createdObservationId = new IdType(respEntry.getLocation());
|
||||||
assertEquals("Patient", createdId.getResourceType());
|
assertEquals("Patient", createdObservationId.getResourceType());
|
||||||
assertEquals("1", createdId.getVersionIdPart());
|
assertEquals("1", createdObservationId.getVersionIdPart());
|
||||||
|
|
||||||
respEntry = output.getEntry().get(1).getResponse();
|
respEntry = output.getEntry().get(1).getResponse();
|
||||||
assertEquals("200 OK", respEntry.getStatus());
|
assertEquals("200 OK", respEntry.getStatus());
|
||||||
createdId = new IdType(respEntry.getLocation());
|
createdObservationId = new IdType(respEntry.getLocation());
|
||||||
assertEquals("Observation", createdId.getResourceType());
|
assertEquals("Observation", createdObservationId.getResourceType());
|
||||||
assertEquals("1", createdId.getVersionIdPart());
|
assertEquals("1", createdObservationId.getVersionIdPart());
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Searches for both resources should still work and the reference
|
||||||
|
* should be substituted correctly
|
||||||
|
*/
|
||||||
|
// Patient
|
||||||
|
map = new SearchParameterMap();
|
||||||
|
map.setLoadSynchronous(true);
|
||||||
|
map.add(Patient.SP_IDENTIFIER, new TokenParam("foo", "bar"));
|
||||||
|
search = myPatientDao.search(map);
|
||||||
|
assertThat(toUnqualifiedVersionlessIdValues(search), contains(createdPatientId.toUnqualifiedVersionless().getValue()));
|
||||||
|
pat = (Patient) search.getResources(0,1).get(0);
|
||||||
|
assertEquals("foo", pat.getIdentifierFirstRep().getSystem());
|
||||||
|
// Observation
|
||||||
|
map = new SearchParameterMap();
|
||||||
|
map.setLoadSynchronous(true);
|
||||||
|
map.add(Observation.SP_IDENTIFIER, new TokenParam("foo", "dog"));
|
||||||
|
search = myObservationDao.search(map);
|
||||||
|
assertThat(toUnqualifiedVersionlessIdValues(search), contains(createdObservationId.toUnqualifiedVersionless().getValue()));
|
||||||
|
obs = (Observation) search.getResources(0,1).get(0);
|
||||||
|
assertEquals("foo", obs.getIdentifierFirstRep().getSystem());
|
||||||
|
assertEquals(createdPatientId.toUnqualifiedVersionless().getValue(), obs.getSubject().getReference());
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now run the transaction, but this time with an actual
|
||||||
|
* change to the Observation
|
||||||
|
*/
|
||||||
|
|
||||||
|
input = new Bundle();
|
||||||
|
pat = new Patient();
|
||||||
|
pat.setId(IdType.newRandomUuid());
|
||||||
|
pat.addIdentifier().setSystem("foo").setValue("bar");
|
||||||
|
input
|
||||||
|
.addEntry()
|
||||||
|
.setResource(pat)
|
||||||
|
.setFullUrl(pat.getId())
|
||||||
|
.getRequest()
|
||||||
|
.setMethod(HTTPVerb.POST)
|
||||||
|
.setUrl("/Patient")
|
||||||
|
.setIfNoneExist("Patient?identifier=foo|bar");
|
||||||
|
obs = new Observation();
|
||||||
|
obs.addIdentifier().setSystem("foo").setValue("dog");
|
||||||
|
obs.setStatus(ObservationStatus.FINAL);
|
||||||
|
obs.getSubject().setReference(pat.getId());
|
||||||
|
input
|
||||||
|
.addEntry()
|
||||||
|
.setResource(obs)
|
||||||
|
.getRequest()
|
||||||
|
.setMethod(HTTPVerb.PUT)
|
||||||
|
.setUrl("/Observation?identifier=foo|dog");
|
||||||
|
output = mySystemDao.transaction(mySrd, input);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Observation should now be version 2
|
||||||
|
*/
|
||||||
|
respEntry = output.getEntry().get(0).getResponse();
|
||||||
|
assertEquals("200 OK", respEntry.getStatus());
|
||||||
|
createdObservationId = new IdType(respEntry.getLocation());
|
||||||
|
assertEquals("Patient", createdObservationId.getResourceType());
|
||||||
|
assertEquals("1", createdObservationId.getVersionIdPart());
|
||||||
|
|
||||||
|
respEntry = output.getEntry().get(1).getResponse();
|
||||||
|
assertEquals("200 OK", respEntry.getStatus());
|
||||||
|
createdObservationId = new IdType(respEntry.getLocation());
|
||||||
|
assertEquals("Observation", createdObservationId.getResourceType());
|
||||||
|
assertEquals("2", createdObservationId.getVersionIdPart());
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Searches for both resources should still work and the reference
|
||||||
|
* should be substituted correctly
|
||||||
|
*/
|
||||||
|
// Patient
|
||||||
|
map = new SearchParameterMap();
|
||||||
|
map.setLoadSynchronous(true);
|
||||||
|
map.add(Patient.SP_IDENTIFIER, new TokenParam("foo", "bar"));
|
||||||
|
search = myPatientDao.search(map);
|
||||||
|
assertThat(toUnqualifiedVersionlessIdValues(search), contains(createdPatientId.toUnqualifiedVersionless().getValue()));
|
||||||
|
pat = (Patient) search.getResources(0,1).get(0);
|
||||||
|
assertEquals("foo", pat.getIdentifierFirstRep().getSystem());
|
||||||
|
// Observation
|
||||||
|
map = new SearchParameterMap();
|
||||||
|
map.setLoadSynchronous(true);
|
||||||
|
map.add(Observation.SP_IDENTIFIER, new TokenParam("foo", "dog"));
|
||||||
|
search = myObservationDao.search(map);
|
||||||
|
assertThat(toUnqualifiedVersionlessIdValues(search), contains(createdObservationId.toUnqualifiedVersionless().getValue()));
|
||||||
|
obs = (Observation) search.getResources(0,1).get(0);
|
||||||
|
assertEquals("foo", obs.getIdentifierFirstRep().getSystem());
|
||||||
|
assertEquals(createdPatientId.toUnqualifiedVersionless().getValue(), obs.getSubject().getReference());
|
||||||
|
assertEquals(ObservationStatus.FINAL, obs.getStatus());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@ import ca.uhn.fhir.jpa.config.WebsocketDispatcherConfig;
|
||||||
import ca.uhn.fhir.jpa.dao.data.ISearchDao;
|
import ca.uhn.fhir.jpa.dao.data.ISearchDao;
|
||||||
import ca.uhn.fhir.jpa.dao.dstu3.BaseJpaDstu3Test;
|
import ca.uhn.fhir.jpa.dao.dstu3.BaseJpaDstu3Test;
|
||||||
import ca.uhn.fhir.jpa.dao.dstu3.SearchParamRegistryDstu3;
|
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.DatabaseBackedPagingProvider;
|
||||||
import ca.uhn.fhir.jpa.search.ISearchCoordinatorSvc;
|
import ca.uhn.fhir.jpa.search.ISearchCoordinatorSvc;
|
||||||
import ca.uhn.fhir.jpa.subscription.email.SubscriptionEmailInterceptor;
|
import ca.uhn.fhir.jpa.subscription.email.SubscriptionEmailInterceptor;
|
||||||
|
@ -54,16 +53,16 @@ public abstract class BaseResourceProviderDstu3Test extends BaseJpaDstu3Test {
|
||||||
protected static CloseableHttpClient ourHttpClient;
|
protected static CloseableHttpClient ourHttpClient;
|
||||||
protected static int ourPort;
|
protected static int ourPort;
|
||||||
protected static RestfulServer ourRestServer;
|
protected static RestfulServer ourRestServer;
|
||||||
private static Server ourServer;
|
|
||||||
protected static String ourServerBase;
|
protected static String ourServerBase;
|
||||||
protected static GenericWebApplicationContext ourWebApplicationContext;
|
protected static GenericWebApplicationContext ourWebApplicationContext;
|
||||||
private TerminologyUploaderProvider myTerminologyUploaderProvider;
|
|
||||||
protected static SearchParamRegistryDstu3 ourSearchParamRegistry;
|
protected static SearchParamRegistryDstu3 ourSearchParamRegistry;
|
||||||
protected static DatabaseBackedPagingProvider ourPagingProvider;
|
protected static DatabaseBackedPagingProvider ourPagingProvider;
|
||||||
protected static SubscriptionRestHookInterceptor ourRestHookSubscriptionInterceptor;
|
protected static SubscriptionRestHookInterceptor ourRestHookSubscriptionInterceptor;
|
||||||
protected static SubscriptionEmailInterceptor ourEmailSubscriptionInterceptor;
|
protected static SubscriptionEmailInterceptor ourEmailSubscriptionInterceptor;
|
||||||
protected static ISearchDao mySearchEntityDao;
|
protected static ISearchDao mySearchEntityDao;
|
||||||
protected static ISearchCoordinatorSvc mySearchCoordinatorSvc;
|
protected static ISearchCoordinatorSvc mySearchCoordinatorSvc;
|
||||||
|
private static Server ourServer;
|
||||||
|
private TerminologyUploaderProviderDstu3 myTerminologyUploaderProvider;
|
||||||
|
|
||||||
public BaseResourceProviderDstu3Test() {
|
public BaseResourceProviderDstu3Test() {
|
||||||
super();
|
super();
|
||||||
|
@ -93,7 +92,7 @@ public abstract class BaseResourceProviderDstu3Test extends BaseJpaDstu3Test {
|
||||||
|
|
||||||
ourRestServer.getFhirContext().setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator());
|
ourRestServer.getFhirContext().setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator());
|
||||||
|
|
||||||
myTerminologyUploaderProvider = myAppCtx.getBean(TerminologyUploaderProvider.class);
|
myTerminologyUploaderProvider = myAppCtx.getBean(TerminologyUploaderProviderDstu3.class);
|
||||||
|
|
||||||
ourRestServer.setPlainProviders(mySystemProvider, myTerminologyUploaderProvider);
|
ourRestServer.setPlainProviders(mySystemProvider, myTerminologyUploaderProvider);
|
||||||
|
|
||||||
|
|
|
@ -32,12 +32,6 @@ public class ResourceProviderDstu3CodeSystemTest extends BaseResourceProviderDst
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResourceProviderDstu3CodeSystemTest.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResourceProviderDstu3CodeSystemTest.class);
|
||||||
private IIdType myExtensionalVsId;
|
private IIdType myExtensionalVsId;
|
||||||
|
|
||||||
@AfterClass
|
|
||||||
public static void afterClassClearContext() {
|
|
||||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
@Transactional
|
@Transactional
|
||||||
public void before02() throws IOException {
|
public void before02() throws IOException {
|
||||||
|
@ -64,7 +58,7 @@ public class ResourceProviderDstu3CodeSystemTest extends BaseResourceProviderDst
|
||||||
ourLog.info(resp);
|
ourLog.info(resp);
|
||||||
|
|
||||||
assertEquals("name", respParam.getParameter().get(0).getName());
|
assertEquals("name", respParam.getParameter().get(0).getName());
|
||||||
assertEquals(("Unknown"), ((StringType)respParam.getParameter().get(0).getValue()).getValue());
|
assertEquals(("SYSTEM NAME"), ((StringType)respParam.getParameter().get(0).getValue()).getValue());
|
||||||
assertEquals("display", respParam.getParameter().get(1).getName());
|
assertEquals("display", respParam.getParameter().get(1).getName());
|
||||||
assertEquals("Parent A", ((StringType)respParam.getParameter().get(1).getValue()).getValue());
|
assertEquals("Parent A", ((StringType)respParam.getParameter().get(1).getValue()).getValue());
|
||||||
assertEquals("abstract", respParam.getParameter().get(2).getName());
|
assertEquals("abstract", respParam.getParameter().get(2).getName());
|
||||||
|
@ -84,7 +78,7 @@ public class ResourceProviderDstu3CodeSystemTest extends BaseResourceProviderDst
|
||||||
ourLog.info(resp);
|
ourLog.info(resp);
|
||||||
|
|
||||||
assertEquals("name", respParam.getParameter().get(0).getName());
|
assertEquals("name", respParam.getParameter().get(0).getName());
|
||||||
assertEquals(("Unknown"), ((StringType)respParam.getParameter().get(0).getValue()).getValue());
|
assertEquals(("SYSTEM NAME"), ((StringType)respParam.getParameter().get(0).getValue()).getValue());
|
||||||
assertEquals("display", respParam.getParameter().get(1).getName());
|
assertEquals("display", respParam.getParameter().get(1).getName());
|
||||||
assertEquals("Parent A", ((StringType)respParam.getParameter().get(1).getValue()).getValue());
|
assertEquals("Parent A", ((StringType)respParam.getParameter().get(1).getValue()).getValue());
|
||||||
assertEquals("abstract", respParam.getParameter().get(2).getName());
|
assertEquals("abstract", respParam.getParameter().get(2).getName());
|
||||||
|
@ -272,5 +266,10 @@ public class ResourceProviderDstu3CodeSystemTest extends BaseResourceProviderDst
|
||||||
assertEquals(false, ((BooleanType)respParam.getParameter().get(2).getValue()).booleanValue());
|
assertEquals(false, ((BooleanType)respParam.getParameter().get(2).getValue()).booleanValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void afterClassClearContext() {
|
||||||
|
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package ca.uhn.fhir.jpa.provider.dstu3;
|
package ca.uhn.fhir.jpa.provider.dstu3;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.containsString;
|
||||||
import static org.hamcrest.Matchers.greaterThan;
|
import static org.hamcrest.Matchers.greaterThan;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertThat;
|
import static org.junit.Assert.assertThat;
|
||||||
|
@ -14,6 +15,7 @@ import java.util.List;
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipOutputStream;
|
import java.util.zip.ZipOutputStream;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.hl7.fhir.dstu3.model.Attachment;
|
import org.hl7.fhir.dstu3.model.Attachment;
|
||||||
import org.hl7.fhir.dstu3.model.IntegerType;
|
import org.hl7.fhir.dstu3.model.IntegerType;
|
||||||
|
@ -31,167 +33,6 @@ public class TerminologyUploaderProviderDstu3Test extends BaseResourceProviderDs
|
||||||
|
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TerminologyUploaderProviderDstu3Test.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TerminologyUploaderProviderDstu3Test.class);
|
||||||
|
|
||||||
@AfterClass
|
|
||||||
public static void afterClassClearContext() {
|
|
||||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testUploadSct() throws Exception {
|
|
||||||
byte[] packageBytes = createSctZip();
|
|
||||||
|
|
||||||
//@formatter:off
|
|
||||||
Parameters respParam = ourClient
|
|
||||||
.operation()
|
|
||||||
.onServer()
|
|
||||||
.named("upload-external-code-system")
|
|
||||||
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI))
|
|
||||||
.andParameter("package", new Attachment().setData(packageBytes))
|
|
||||||
.execute();
|
|
||||||
//@formatter:on
|
|
||||||
|
|
||||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
|
|
||||||
ourLog.info(resp);
|
|
||||||
|
|
||||||
assertThat(((IntegerType)respParam.getParameter().get(0).getValue()).getValue(), greaterThan(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testUploadLoinc() throws Exception {
|
|
||||||
byte[] packageBytes = createLoincZip();
|
|
||||||
|
|
||||||
//@formatter:off
|
|
||||||
Parameters respParam = ourClient
|
|
||||||
.operation()
|
|
||||||
.onServer()
|
|
||||||
.named("upload-external-code-system")
|
|
||||||
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.LOINC_URI))
|
|
||||||
.andParameter("package", new Attachment().setData(packageBytes))
|
|
||||||
.execute();
|
|
||||||
//@formatter:on
|
|
||||||
|
|
||||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
|
|
||||||
ourLog.info(resp);
|
|
||||||
|
|
||||||
assertThat(((IntegerType)respParam.getParameter().get(0).getValue()).getValue(), greaterThan(1));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Try uploading a second time
|
|
||||||
*/
|
|
||||||
|
|
||||||
//@formatter:off
|
|
||||||
respParam = ourClient
|
|
||||||
.operation()
|
|
||||||
.onServer()
|
|
||||||
.named("upload-external-code-system")
|
|
||||||
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.LOINC_URI))
|
|
||||||
.andParameter("package", new Attachment().setData(packageBytes))
|
|
||||||
.execute();
|
|
||||||
//@formatter:on
|
|
||||||
|
|
||||||
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
|
|
||||||
ourLog.info(resp);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testUploadSctLocalFile() throws Exception {
|
|
||||||
byte[] packageBytes = createSctZip();
|
|
||||||
File tempFile = File.createTempFile("tmp", ".zip");
|
|
||||||
tempFile.deleteOnExit();
|
|
||||||
|
|
||||||
FileOutputStream fos = new FileOutputStream(tempFile);
|
|
||||||
fos.write(packageBytes);
|
|
||||||
fos.close();
|
|
||||||
|
|
||||||
//@formatter:off
|
|
||||||
Parameters respParam = ourClient
|
|
||||||
.operation()
|
|
||||||
.onServer()
|
|
||||||
.named("upload-external-code-system")
|
|
||||||
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI))
|
|
||||||
.andParameter("localfile", new StringType(tempFile.getAbsolutePath()))
|
|
||||||
.execute();
|
|
||||||
//@formatter:on
|
|
||||||
|
|
||||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
|
|
||||||
ourLog.info(resp);
|
|
||||||
|
|
||||||
assertThat(((IntegerType)respParam.getParameter().get(0).getValue()).getValue(), greaterThan(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testUploadInvalidUrl() throws Exception {
|
|
||||||
byte[] packageBytes = createSctZip();
|
|
||||||
|
|
||||||
//@formatter:off
|
|
||||||
try {
|
|
||||||
ourClient
|
|
||||||
.operation()
|
|
||||||
.onServer()
|
|
||||||
.named("upload-external-code-system")
|
|
||||||
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI + "FOO"))
|
|
||||||
.andParameter("package", new Attachment().setData(packageBytes))
|
|
||||||
.execute();
|
|
||||||
fail();
|
|
||||||
} catch (InvalidRequestException e) {
|
|
||||||
assertEquals("HTTP 400 Bad Request: Unknown URL: http://snomed.info/sctFOO", e.getMessage());
|
|
||||||
}
|
|
||||||
//@formatter:on
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testUploadMissingUrl() throws Exception {
|
|
||||||
byte[] packageBytes = createSctZip();
|
|
||||||
|
|
||||||
//@formatter:off
|
|
||||||
try {
|
|
||||||
ourClient
|
|
||||||
.operation()
|
|
||||||
.onServer()
|
|
||||||
.named("upload-external-code-system")
|
|
||||||
.withParameter(Parameters.class, "package", new Attachment().setData(packageBytes))
|
|
||||||
.execute();
|
|
||||||
fail();
|
|
||||||
} catch (InvalidRequestException e) {
|
|
||||||
assertEquals("HTTP 400 Bad Request: Unknown URL: ", e.getMessage());
|
|
||||||
}
|
|
||||||
//@formatter:on
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testUploadMissingPackage() throws Exception {
|
|
||||||
//@formatter:off
|
|
||||||
try {
|
|
||||||
ourClient
|
|
||||||
.operation()
|
|
||||||
.onServer()
|
|
||||||
.named("upload-external-code-system")
|
|
||||||
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI))
|
|
||||||
.execute();
|
|
||||||
fail();
|
|
||||||
} catch (InvalidRequestException e) {
|
|
||||||
assertEquals("HTTP 400 Bad Request: No 'localfile' or 'package' parameter, or package had no data", e.getMessage());
|
|
||||||
}
|
|
||||||
//@formatter:on
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] createSctZip() throws IOException {
|
|
||||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
|
||||||
ZipOutputStream zos = new ZipOutputStream(bos);
|
|
||||||
|
|
||||||
List<String> inputNames = Arrays.asList("sct2_Concept_Full_INT_20160131.txt","sct2_Concept_Full-en_INT_20160131.txt","sct2_Description_Full-en_INT_20160131.txt","sct2_Identifier_Full_INT_20160131.txt","sct2_Relationship_Full_INT_20160131.txt","sct2_StatedRelationship_Full_INT_20160131.txt","sct2_TextDefinition_Full-en_INT_20160131.txt");
|
|
||||||
for (String nextName : inputNames) {
|
|
||||||
zos.putNextEntry(new ZipEntry("SnomedCT_Release_INT_20160131_Full/Terminology/" + nextName));
|
|
||||||
zos.write(IOUtils.toByteArray(getClass().getResourceAsStream("/sct/" + nextName)));
|
|
||||||
}
|
|
||||||
zos.close();
|
|
||||||
byte[] packageBytes = bos.toByteArray();
|
|
||||||
return packageBytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] createLoincZip() throws IOException {
|
private byte[] createLoincZip() throws IOException {
|
||||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||||
ZipOutputStream zos = new ZipOutputStream(bos);
|
ZipOutputStream zos = new ZipOutputStream(bos);
|
||||||
|
@ -206,4 +47,170 @@ public class TerminologyUploaderProviderDstu3Test extends BaseResourceProviderDs
|
||||||
return packageBytes;
|
return packageBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private byte[] createSctZip() throws IOException {
|
||||||
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||||
|
ZipOutputStream zos = new ZipOutputStream(bos);
|
||||||
|
|
||||||
|
List<String> inputNames = Arrays.asList("sct2_Concept_Full_INT_20160131.txt","sct2_Concept_Full-en_INT_20160131.txt","sct2_Description_Full-en_INT_20160131.txt","sct2_Identifier_Full_INT_20160131.txt","sct2_Relationship_Full_INT_20160131.txt","sct2_StatedRelationship_Full_INT_20160131.txt","sct2_TextDefinition_Full-en_INT_20160131.txt");
|
||||||
|
for (String nextName : inputNames) {
|
||||||
|
zos.putNextEntry(new ZipEntry("SnomedCT_Release_INT_20160131_Full/Terminology/" + nextName));
|
||||||
|
byte[] b = IOUtils.toByteArray(getClass().getResourceAsStream("/sct/" + nextName));
|
||||||
|
zos.write(b);
|
||||||
|
}
|
||||||
|
zos.close();
|
||||||
|
byte[] packageBytes = bos.toByteArray();
|
||||||
|
return packageBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUploadInvalidUrl() throws Exception {
|
||||||
|
byte[] packageBytes = createSctZip();
|
||||||
|
|
||||||
|
try {
|
||||||
|
ourClient
|
||||||
|
.operation()
|
||||||
|
.onServer()
|
||||||
|
.named("upload-external-code-system")
|
||||||
|
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI + "FOO"))
|
||||||
|
.andParameter("package", new Attachment().setUrl("foo").setData(packageBytes))
|
||||||
|
.execute();
|
||||||
|
fail();
|
||||||
|
} catch (InvalidRequestException e) {
|
||||||
|
assertEquals("HTTP 400 Bad Request: Unknown URL: http://snomed.info/sctFOO", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUploadLoinc() throws Exception {
|
||||||
|
byte[] packageBytes = createLoincZip();
|
||||||
|
|
||||||
|
Parameters respParam = ourClient
|
||||||
|
.operation()
|
||||||
|
.onServer()
|
||||||
|
.named("upload-external-code-system")
|
||||||
|
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.LOINC_URI))
|
||||||
|
.andParameter("package", new Attachment().setUrl("file.zip").setData(packageBytes))
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
|
||||||
|
ourLog.info(resp);
|
||||||
|
|
||||||
|
assertThat(((IntegerType)respParam.getParameter().get(0).getValue()).getValue(), greaterThan(1));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try uploading a second time
|
||||||
|
*/
|
||||||
|
|
||||||
|
respParam = ourClient
|
||||||
|
.operation()
|
||||||
|
.onServer()
|
||||||
|
.named("upload-external-code-system")
|
||||||
|
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.LOINC_URI))
|
||||||
|
.andParameter("package", new Attachment().setUrl("file.zip").setData(packageBytes))
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
|
||||||
|
ourLog.info(resp);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUploadMissingPackage() throws Exception {
|
||||||
|
byte[] packageBytes = createLoincZip();
|
||||||
|
try {
|
||||||
|
ourClient
|
||||||
|
.operation()
|
||||||
|
.onServer()
|
||||||
|
.named("upload-external-code-system")
|
||||||
|
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI))
|
||||||
|
.andParameter("package", new Attachment().setData(packageBytes))
|
||||||
|
.execute();
|
||||||
|
fail();
|
||||||
|
} catch (UnprocessableEntityException e) {
|
||||||
|
assertThat(e.getMessage(), containsString("Package is missing mandatory url element"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUploadMissingUrl() throws Exception {
|
||||||
|
byte[] packageBytes = createSctZip();
|
||||||
|
|
||||||
|
try {
|
||||||
|
ourClient
|
||||||
|
.operation()
|
||||||
|
.onServer()
|
||||||
|
.named("upload-external-code-system")
|
||||||
|
.withParameter(Parameters.class, "package", new Attachment().setUrl("foo").setData(packageBytes))
|
||||||
|
.execute();
|
||||||
|
fail();
|
||||||
|
} catch (InvalidRequestException e) {
|
||||||
|
assertEquals("HTTP 400 Bad Request: Unknown URL: ", e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUploadPackageMissingUrl() throws Exception {
|
||||||
|
try {
|
||||||
|
ourClient
|
||||||
|
.operation()
|
||||||
|
.onServer()
|
||||||
|
.named("upload-external-code-system")
|
||||||
|
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI))
|
||||||
|
.execute();
|
||||||
|
fail();
|
||||||
|
} catch (InvalidRequestException e) {
|
||||||
|
assertEquals("HTTP 400 Bad Request: No 'localfile' or 'package' parameter, or package had no data", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUploadSct() throws Exception {
|
||||||
|
byte[] packageBytes = createSctZip();
|
||||||
|
|
||||||
|
Parameters respParam = ourClient
|
||||||
|
.operation()
|
||||||
|
.onServer()
|
||||||
|
.named("upload-external-code-system")
|
||||||
|
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI))
|
||||||
|
.andParameter("package", new Attachment().setUrl("file.zip").setData(packageBytes))
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
|
||||||
|
ourLog.info(resp);
|
||||||
|
|
||||||
|
assertThat(((IntegerType)respParam.getParameter().get(0).getValue()).getValue(), greaterThan(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUploadSctLocalFile() throws Exception {
|
||||||
|
byte[] packageBytes = createSctZip();
|
||||||
|
File tempFile = File.createTempFile("tmp", ".zip");
|
||||||
|
tempFile.deleteOnExit();
|
||||||
|
|
||||||
|
FileOutputStream fos = new FileOutputStream(tempFile);
|
||||||
|
fos.write(packageBytes);
|
||||||
|
fos.close();
|
||||||
|
|
||||||
|
ourLog.info("File is: {}", tempFile.getAbsolutePath());
|
||||||
|
|
||||||
|
Parameters respParam = ourClient
|
||||||
|
.operation()
|
||||||
|
.onServer()
|
||||||
|
.named("upload-external-code-system")
|
||||||
|
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI))
|
||||||
|
.andParameter("localfile", new StringType(tempFile.getAbsolutePath()))
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
|
||||||
|
ourLog.info(resp);
|
||||||
|
|
||||||
|
assertThat(((IntegerType)respParam.getParameter().get(0).getValue()).getValue(), greaterThan(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void afterClassClearContext() {
|
||||||
|
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@ import ca.uhn.fhir.jpa.config.WebsocketDispatcherConfig;
|
||||||
import ca.uhn.fhir.jpa.dao.data.ISearchDao;
|
import ca.uhn.fhir.jpa.dao.data.ISearchDao;
|
||||||
import ca.uhn.fhir.jpa.dao.r4.BaseJpaR4Test;
|
import ca.uhn.fhir.jpa.dao.r4.BaseJpaR4Test;
|
||||||
import ca.uhn.fhir.jpa.dao.r4.SearchParamRegistryR4;
|
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.DatabaseBackedPagingProvider;
|
||||||
import ca.uhn.fhir.jpa.search.ISearchCoordinatorSvc;
|
import ca.uhn.fhir.jpa.search.ISearchCoordinatorSvc;
|
||||||
import ca.uhn.fhir.jpa.subscription.resthook.SubscriptionRestHookInterceptor;
|
import ca.uhn.fhir.jpa.subscription.resthook.SubscriptionRestHookInterceptor;
|
||||||
|
@ -59,7 +58,7 @@ public abstract class BaseResourceProviderR4Test extends BaseJpaR4Test {
|
||||||
protected static ISearchCoordinatorSvc mySearchCoordinatorSvc;
|
protected static ISearchCoordinatorSvc mySearchCoordinatorSvc;
|
||||||
private static Server ourServer;
|
private static Server ourServer;
|
||||||
protected static GenericWebApplicationContext ourWebApplicationContext;
|
protected static GenericWebApplicationContext ourWebApplicationContext;
|
||||||
private TerminologyUploaderProvider myTerminologyUploaderProvider;
|
private TerminologyUploaderProviderR4 myTerminologyUploaderProvider;
|
||||||
private Object ourGraphQLProvider;
|
private Object ourGraphQLProvider;
|
||||||
private boolean ourRestHookSubscriptionInterceptorRequested;
|
private boolean ourRestHookSubscriptionInterceptorRequested;
|
||||||
|
|
||||||
|
@ -90,7 +89,7 @@ public abstract class BaseResourceProviderR4Test extends BaseJpaR4Test {
|
||||||
|
|
||||||
ourRestServer.getFhirContext().setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator());
|
ourRestServer.getFhirContext().setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator());
|
||||||
|
|
||||||
myTerminologyUploaderProvider = myAppCtx.getBean(TerminologyUploaderProvider.class);
|
myTerminologyUploaderProvider = myAppCtx.getBean(TerminologyUploaderProviderR4.class);
|
||||||
ourGraphQLProvider = myAppCtx.getBean("myGraphQLProvider");
|
ourGraphQLProvider = myAppCtx.getBean("myGraphQLProvider");
|
||||||
|
|
||||||
ourRestServer.setPlainProviders(mySystemProvider, myTerminologyUploaderProvider, ourGraphQLProvider);
|
ourRestServer.setPlainProviders(mySystemProvider, myTerminologyUploaderProvider, ourGraphQLProvider);
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
package ca.uhn.fhir.jpa.provider.r4;
|
package ca.uhn.fhir.jpa.provider.r4;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.greaterThan;
|
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
|
||||||
import static org.junit.Assert.assertEquals;
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
import static org.junit.Assert.assertThat;
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
import static org.junit.Assert.fail;
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.hl7.fhir.r4.model.*;
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
@ -14,48 +17,59 @@ import java.util.List;
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipOutputStream;
|
import java.util.zip.ZipOutputStream;
|
||||||
|
|
||||||
import org.apache.commons.io.IOUtils;
|
import static org.hamcrest.Matchers.greaterThan;
|
||||||
import org.hl7.fhir.r4.model.Attachment;
|
import static org.junit.Assert.*;
|
||||||
import org.hl7.fhir.r4.model.IntegerType;
|
|
||||||
import org.hl7.fhir.r4.model.Parameters;
|
|
||||||
import org.hl7.fhir.r4.model.StringType;
|
|
||||||
import org.hl7.fhir.r4.model.UriType;
|
|
||||||
import org.junit.AfterClass;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
|
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
|
||||||
import ca.uhn.fhir.util.TestUtil;
|
|
||||||
|
|
||||||
public class TerminologyUploaderProviderR4Test extends BaseResourceProviderR4Test {
|
public class TerminologyUploaderProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
|
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TerminologyUploaderProviderR4Test.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TerminologyUploaderProviderR4Test.class);
|
||||||
|
|
||||||
@AfterClass
|
private byte[] createLoincZip() throws IOException {
|
||||||
public static void afterClassClearContext() {
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
ZipOutputStream zos = new ZipOutputStream(bos);
|
||||||
|
|
||||||
|
zos.putNextEntry(new ZipEntry("loinc.csv"));
|
||||||
|
zos.write(IOUtils.toByteArray(getClass().getResourceAsStream("/loinc/loinc.csv")));
|
||||||
|
zos.putNextEntry(new ZipEntry("LOINC_2.54_MULTI-AXIAL_HIERARCHY.CSV"));
|
||||||
|
zos.write(IOUtils.toByteArray(getClass().getResourceAsStream("/loinc/LOINC_2.54_MULTI-AXIAL_HIERARCHY.CSV")));
|
||||||
|
zos.close();
|
||||||
|
|
||||||
|
byte[] packageBytes = bos.toByteArray();
|
||||||
|
return packageBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private byte[] createSctZip() throws IOException {
|
||||||
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||||
|
ZipOutputStream zos = new ZipOutputStream(bos);
|
||||||
|
|
||||||
|
List<String> inputNames = Arrays.asList("sct2_Concept_Full_INT_20160131.txt", "sct2_Concept_Full-en_INT_20160131.txt", "sct2_Description_Full-en_INT_20160131.txt", "sct2_Identifier_Full_INT_20160131.txt", "sct2_Relationship_Full_INT_20160131.txt", "sct2_StatedRelationship_Full_INT_20160131.txt", "sct2_TextDefinition_Full-en_INT_20160131.txt");
|
||||||
|
for (String nextName : inputNames) {
|
||||||
|
zos.putNextEntry(new ZipEntry("SnomedCT_Release_INT_20160131_Full/Terminology/" + nextName));
|
||||||
|
zos.write(IOUtils.toByteArray(getClass().getResourceAsStream("/sct/" + nextName)));
|
||||||
|
}
|
||||||
|
zos.close();
|
||||||
|
byte[] packageBytes = bos.toByteArray();
|
||||||
|
return packageBytes;
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUploadSct() throws Exception {
|
public void testUploadInvalidUrl() throws Exception {
|
||||||
byte[] packageBytes = createSctZip();
|
byte[] packageBytes = createSctZip();
|
||||||
|
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
Parameters respParam = myClient
|
try {
|
||||||
|
myClient
|
||||||
.operation()
|
.operation()
|
||||||
.onServer()
|
.onServer()
|
||||||
.named("upload-external-code-system")
|
.named("upload-external-code-system")
|
||||||
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI))
|
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI + "FOO"))
|
||||||
.andParameter("package", new Attachment().setData(packageBytes))
|
.andParameter("package", new Attachment().setUrl("file.zip").setData(packageBytes))
|
||||||
.execute();
|
.execute();
|
||||||
|
fail();
|
||||||
|
} catch (InvalidRequestException e) {
|
||||||
|
assertEquals("HTTP 400 Bad Request: Unknown URL: http://snomed.info/sctFOO", e.getMessage());
|
||||||
|
}
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
|
|
||||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
|
|
||||||
ourLog.info(resp);
|
|
||||||
|
|
||||||
assertThat(((IntegerType)respParam.getParameter().get(0).getValue()).getValue(), greaterThan(1));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -68,14 +82,14 @@ public class TerminologyUploaderProviderR4Test extends BaseResourceProviderR4Tes
|
||||||
.onServer()
|
.onServer()
|
||||||
.named("upload-external-code-system")
|
.named("upload-external-code-system")
|
||||||
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.LOINC_URI))
|
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.LOINC_URI))
|
||||||
.andParameter("package", new Attachment().setData(packageBytes))
|
.andParameter("package", new Attachment().setUrl("file.zip").setData(packageBytes))
|
||||||
.execute();
|
.execute();
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
|
|
||||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
|
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
|
||||||
ourLog.info(resp);
|
ourLog.info(resp);
|
||||||
|
|
||||||
assertThat(((IntegerType)respParam.getParameter().get(0).getValue()).getValue(), greaterThan(1));
|
assertThat(((IntegerType) respParam.getParameter().get(0).getValue()).getValue(), greaterThan(1));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Try uploading a second time
|
* Try uploading a second time
|
||||||
|
@ -87,7 +101,7 @@ public class TerminologyUploaderProviderR4Test extends BaseResourceProviderR4Tes
|
||||||
.onServer()
|
.onServer()
|
||||||
.named("upload-external-code-system")
|
.named("upload-external-code-system")
|
||||||
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.LOINC_URI))
|
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.LOINC_URI))
|
||||||
.andParameter("package", new Attachment().setData(packageBytes))
|
.andParameter("package", new Attachment().setUrl("file.zip").setData(packageBytes))
|
||||||
.execute();
|
.execute();
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
|
|
||||||
|
@ -96,6 +110,62 @@ public class TerminologyUploaderProviderR4Test extends BaseResourceProviderR4Tes
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUploadMissingPackage() throws Exception {
|
||||||
|
//@formatter:off
|
||||||
|
try {
|
||||||
|
myClient
|
||||||
|
.operation()
|
||||||
|
.onServer()
|
||||||
|
.named("upload-external-code-system")
|
||||||
|
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI))
|
||||||
|
.execute();
|
||||||
|
fail();
|
||||||
|
} catch (InvalidRequestException e) {
|
||||||
|
assertEquals("HTTP 400 Bad Request: No 'localfile' or 'package' parameter, or package had no data", e.getMessage());
|
||||||
|
}
|
||||||
|
//@formatter:on
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUploadMissingUrl() throws Exception {
|
||||||
|
byte[] packageBytes = createSctZip();
|
||||||
|
|
||||||
|
//@formatter:off
|
||||||
|
try {
|
||||||
|
myClient
|
||||||
|
.operation()
|
||||||
|
.onServer()
|
||||||
|
.named("upload-external-code-system")
|
||||||
|
.withParameter(Parameters.class, "package", new Attachment().setUrl("file.zip").setData(packageBytes))
|
||||||
|
.execute();
|
||||||
|
fail();
|
||||||
|
} catch (InvalidRequestException e) {
|
||||||
|
assertEquals("HTTP 400 Bad Request: Unknown URL: ", e.getMessage());
|
||||||
|
}
|
||||||
|
//@formatter:on
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUploadSct() throws Exception {
|
||||||
|
byte[] packageBytes = createSctZip();
|
||||||
|
|
||||||
|
//@formatter:off
|
||||||
|
Parameters respParam = myClient
|
||||||
|
.operation()
|
||||||
|
.onServer()
|
||||||
|
.named("upload-external-code-system")
|
||||||
|
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI))
|
||||||
|
.andParameter("package", new Attachment().setUrl("file.zip").setData(packageBytes))
|
||||||
|
.execute();
|
||||||
|
//@formatter:on
|
||||||
|
|
||||||
|
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
|
||||||
|
ourLog.info(resp);
|
||||||
|
|
||||||
|
assertThat(((IntegerType) respParam.getParameter().get(0).getValue()).getValue(), greaterThan(1));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUploadSctLocalFile() throws Exception {
|
public void testUploadSctLocalFile() throws Exception {
|
||||||
byte[] packageBytes = createSctZip();
|
byte[] packageBytes = createSctZip();
|
||||||
|
@ -119,91 +189,12 @@ public class TerminologyUploaderProviderR4Test extends BaseResourceProviderR4Tes
|
||||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
|
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
|
||||||
ourLog.info(resp);
|
ourLog.info(resp);
|
||||||
|
|
||||||
assertThat(((IntegerType)respParam.getParameter().get(0).getValue()).getValue(), greaterThan(1));
|
assertThat(((IntegerType) respParam.getParameter().get(0).getValue()).getValue(), greaterThan(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@AfterClass
|
||||||
public void testUploadInvalidUrl() throws Exception {
|
public static void afterClassClearContext() {
|
||||||
byte[] packageBytes = createSctZip();
|
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||||
|
|
||||||
//@formatter:off
|
|
||||||
try {
|
|
||||||
myClient
|
|
||||||
.operation()
|
|
||||||
.onServer()
|
|
||||||
.named("upload-external-code-system")
|
|
||||||
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI + "FOO"))
|
|
||||||
.andParameter("package", new Attachment().setData(packageBytes))
|
|
||||||
.execute();
|
|
||||||
fail();
|
|
||||||
} catch (InvalidRequestException e) {
|
|
||||||
assertEquals("HTTP 400 Bad Request: Unknown URL: http://snomed.info/sctFOO", e.getMessage());
|
|
||||||
}
|
|
||||||
//@formatter:on
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testUploadMissingUrl() throws Exception {
|
|
||||||
byte[] packageBytes = createSctZip();
|
|
||||||
|
|
||||||
//@formatter:off
|
|
||||||
try {
|
|
||||||
myClient
|
|
||||||
.operation()
|
|
||||||
.onServer()
|
|
||||||
.named("upload-external-code-system")
|
|
||||||
.withParameter(Parameters.class, "package", new Attachment().setData(packageBytes))
|
|
||||||
.execute();
|
|
||||||
fail();
|
|
||||||
} catch (InvalidRequestException e) {
|
|
||||||
assertEquals("HTTP 400 Bad Request: Unknown URL: ", e.getMessage());
|
|
||||||
}
|
|
||||||
//@formatter:on
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testUploadMissingPackage() throws Exception {
|
|
||||||
//@formatter:off
|
|
||||||
try {
|
|
||||||
myClient
|
|
||||||
.operation()
|
|
||||||
.onServer()
|
|
||||||
.named("upload-external-code-system")
|
|
||||||
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI))
|
|
||||||
.execute();
|
|
||||||
fail();
|
|
||||||
} catch (InvalidRequestException e) {
|
|
||||||
assertEquals("HTTP 400 Bad Request: No 'localfile' or 'package' parameter, or package had no data", e.getMessage());
|
|
||||||
}
|
|
||||||
//@formatter:on
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] createSctZip() throws IOException {
|
|
||||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
|
||||||
ZipOutputStream zos = new ZipOutputStream(bos);
|
|
||||||
|
|
||||||
List<String> inputNames = Arrays.asList("sct2_Concept_Full_INT_20160131.txt","sct2_Concept_Full-en_INT_20160131.txt","sct2_Description_Full-en_INT_20160131.txt","sct2_Identifier_Full_INT_20160131.txt","sct2_Relationship_Full_INT_20160131.txt","sct2_StatedRelationship_Full_INT_20160131.txt","sct2_TextDefinition_Full-en_INT_20160131.txt");
|
|
||||||
for (String nextName : inputNames) {
|
|
||||||
zos.putNextEntry(new ZipEntry("SnomedCT_Release_INT_20160131_Full/Terminology/" + nextName));
|
|
||||||
zos.write(IOUtils.toByteArray(getClass().getResourceAsStream("/sct/" + nextName)));
|
|
||||||
}
|
|
||||||
zos.close();
|
|
||||||
byte[] packageBytes = bos.toByteArray();
|
|
||||||
return packageBytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] createLoincZip() throws IOException {
|
|
||||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
|
||||||
ZipOutputStream zos = new ZipOutputStream(bos);
|
|
||||||
|
|
||||||
zos.putNextEntry(new ZipEntry("loinc.csv"));
|
|
||||||
zos.write(IOUtils.toByteArray(getClass().getResourceAsStream("/loinc/loinc.csv")));
|
|
||||||
zos.putNextEntry(new ZipEntry("LOINC_2.54_MULTI-AXIAL_HIERARCHY.CSV"));
|
|
||||||
zos.write(IOUtils.toByteArray(getClass().getResourceAsStream("/loinc/LOINC_2.54_MULTI-AXIAL_HIERARCHY.CSV")));
|
|
||||||
zos.close();
|
|
||||||
|
|
||||||
byte[] packageBytes = bos.toByteArray();
|
|
||||||
return packageBytes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,7 +75,7 @@ public class TerminologyLoaderSvcIntegrationDstu3Test extends BaseJpaDstu3Test {
|
||||||
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(parameters));
|
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(parameters));
|
||||||
|
|
||||||
assertEquals("SYSTEM", this.<CodeType>getPropertyPart(parameters, "property", "code").get().getValueAsString());
|
assertEquals("SYSTEM", this.<CodeType>getPropertyPart(parameters, "property", "code").get().getValueAsString());
|
||||||
assertEquals("Heart", this.<CodeType>getPropertyPart(parameters, "property", "value").get().getValueAsString());
|
assertEquals("Heart", this.<StringType>getPropertyPart(parameters, "property", "value").get().getValueAsString());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ import ca.uhn.fhir.jpa.entity.TermConcept;
|
||||||
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink;
|
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink;
|
||||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||||
import ca.uhn.fhir.util.TestUtil;
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.hl7.fhir.r4.model.CodeSystem;
|
import org.hl7.fhir.r4.model.CodeSystem;
|
||||||
|
@ -126,8 +127,8 @@ public class TerminologyLoaderSvcSnomedCtTest {
|
||||||
try {
|
try {
|
||||||
mySvc.loadSnomedCt(list(bos.toByteArray()), details);
|
mySvc.loadSnomedCt(list(bos.toByteArray()), details);
|
||||||
fail();
|
fail();
|
||||||
} catch (InvalidRequestException e) {
|
} catch (UnprocessableEntityException 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());
|
assertThat(e.getMessage(), containsString("Could not find the following mandatory files in input: "));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,8 +11,8 @@ import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||||
import ca.uhn.fhir.util.TestUtil;
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
import org.hl7.fhir.dstu3.model.CodeSystem;
|
import org.hl7.fhir.dstu3.model.CodeSystem;
|
||||||
import org.hl7.fhir.dstu3.model.CodeSystem.CodeSystemContentMode;
|
import org.hl7.fhir.dstu3.model.CodeSystem.CodeSystemContentMode;
|
||||||
import org.hl7.fhir.r4.model.ValueSet;
|
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
|
import org.hl7.fhir.r4.model.ValueSet;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
@ -28,136 +28,6 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
|
||||||
|
|
||||||
private static final String CS_URL = "http://example.com/my_code_system";
|
private static final String CS_URL = "http://example.com/my_code_system";
|
||||||
private static final String CS_URL_2 = "http://example.com/my_code_system2";
|
private static final String CS_URL_2 = "http://example.com/my_code_system2";
|
||||||
|
|
||||||
|
|
||||||
@AfterClass
|
|
||||||
public static void afterClassClearContext() {
|
|
||||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testStoreCodeSystemInvalidCyclicLoop() {
|
|
||||||
CodeSystem codeSystem = new CodeSystem();
|
|
||||||
codeSystem.setUrl(CS_URL);
|
|
||||||
codeSystem.setContent(CodeSystemContentMode.NOTPRESENT);
|
|
||||||
IIdType id = myCodeSystemDao.create(codeSystem, mySrd).getId().toUnqualified();
|
|
||||||
|
|
||||||
ResourceTable table = myResourceTableDao.findOne(id.getIdPartAsLong());
|
|
||||||
|
|
||||||
TermCodeSystemVersion cs = new TermCodeSystemVersion();
|
|
||||||
cs.setResource(table);
|
|
||||||
|
|
||||||
TermConcept parent = new TermConcept();
|
|
||||||
parent.setCodeSystemVersion(cs);
|
|
||||||
parent.setCode("parent");
|
|
||||||
cs.getConcepts().add(parent);
|
|
||||||
|
|
||||||
TermConcept child = new TermConcept();
|
|
||||||
child.setCodeSystemVersion(cs);
|
|
||||||
child.setCode("child");
|
|
||||||
parent.addChild(child, RelationshipTypeEnum.ISA);
|
|
||||||
|
|
||||||
child.addChild(parent, RelationshipTypeEnum.ISA);
|
|
||||||
|
|
||||||
try {
|
|
||||||
// myTermSvc.storeNewCodeSystemVersion(table.getId(), "http://foo", , cs);
|
|
||||||
fail();
|
|
||||||
} catch (InvalidRequestException e) {
|
|
||||||
assertEquals("CodeSystem contains circular reference around code parent", e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testFindCodesAboveAndBelowUnknown() {
|
|
||||||
createCodeSystem();
|
|
||||||
|
|
||||||
assertThat(myTermSvc.findCodesBelow("http://foo", "code"), empty());
|
|
||||||
assertThat(myTermSvc.findCodesBelow(CS_URL, "code"), empty());
|
|
||||||
assertThat(myTermSvc.findCodesAbove("http://foo", "code"), empty());
|
|
||||||
assertThat(myTermSvc.findCodesAbove(CS_URL, "code"), empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testFindCodesBelowA() {
|
|
||||||
IIdType id = createCodeSystem();
|
|
||||||
|
|
||||||
Set<TermConcept> concepts;
|
|
||||||
Set<String> codes;
|
|
||||||
|
|
||||||
concepts = myTermSvc.findCodesBelow(id.getIdPartAsLong(), id.getVersionIdPartAsLong(), "ParentA");
|
|
||||||
codes = toCodes(concepts);
|
|
||||||
assertThat(codes, containsInAnyOrder("ParentA", "childAA", "childAAA", "childAAB", "childAB"));
|
|
||||||
|
|
||||||
concepts = myTermSvc.findCodesBelow(id.getIdPartAsLong(), id.getVersionIdPartAsLong(), "childAA");
|
|
||||||
codes = toCodes(concepts);
|
|
||||||
assertThat(codes, containsInAnyOrder("childAA", "childAAA", "childAAB"));
|
|
||||||
|
|
||||||
// Try an unknown code
|
|
||||||
concepts = myTermSvc.findCodesBelow(id.getIdPartAsLong(), id.getVersionIdPartAsLong(), "FOO_BAD_CODE");
|
|
||||||
codes = toCodes(concepts);
|
|
||||||
assertThat(codes, empty());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testFindCodesBelowBuiltInCodeSystem() {
|
|
||||||
List<VersionIndependentConcept> concepts;
|
|
||||||
Set<String> codes;
|
|
||||||
|
|
||||||
concepts = myTermSvc.findCodesBelow("http://hl7.org/fhir/allergy-clinical-status", "inactive");
|
|
||||||
codes = toCodes(concepts);
|
|
||||||
assertThat(codes, containsInAnyOrder("inactive", "resolved"));
|
|
||||||
|
|
||||||
concepts = myTermSvc.findCodesBelow("http://hl7.org/fhir/allergy-clinical-status", "resolved");
|
|
||||||
codes = toCodes(concepts);
|
|
||||||
assertThat(codes, containsInAnyOrder("resolved"));
|
|
||||||
|
|
||||||
// Unknown code
|
|
||||||
concepts = myTermSvc.findCodesBelow("http://hl7.org/fhir/allergy-clinical-status", "FOO");
|
|
||||||
codes = toCodes(concepts);
|
|
||||||
assertThat(codes, empty());
|
|
||||||
|
|
||||||
// Unknown system
|
|
||||||
concepts = myTermSvc.findCodesBelow("http://hl7.org/fhir/allergy-clinical-status2222", "active");
|
|
||||||
codes = toCodes(concepts);
|
|
||||||
assertThat(codes, empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testFindCodesAboveBuiltInCodeSystem() {
|
|
||||||
List<VersionIndependentConcept> concepts;
|
|
||||||
Set<String> codes;
|
|
||||||
|
|
||||||
concepts = myTermSvc.findCodesAbove("http://hl7.org/fhir/allergy-clinical-status", "active");
|
|
||||||
codes = toCodes(concepts);
|
|
||||||
assertThat(codes, containsInAnyOrder("active"));
|
|
||||||
|
|
||||||
concepts = myTermSvc.findCodesAbove("http://hl7.org/fhir/allergy-clinical-status", "resolved");
|
|
||||||
codes = toCodes(concepts);
|
|
||||||
assertThat(codes, containsInAnyOrder("inactive", "resolved"));
|
|
||||||
|
|
||||||
// Unknown code
|
|
||||||
concepts = myTermSvc.findCodesAbove("http://hl7.org/fhir/allergy-clinical-status", "FOO");
|
|
||||||
codes = toCodes(concepts);
|
|
||||||
assertThat(codes, empty());
|
|
||||||
|
|
||||||
// Unknown system
|
|
||||||
concepts = myTermSvc.findCodesAbove("http://hl7.org/fhir/allergy-clinical-status2222", "active");
|
|
||||||
codes = toCodes(concepts);
|
|
||||||
assertThat(codes, empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testReindexTerminology() {
|
|
||||||
IIdType id = createCodeSystem();
|
|
||||||
|
|
||||||
assertThat(mySystemDao.markAllResourcesForReindexing(), greaterThan(0));
|
|
||||||
|
|
||||||
assertThat(mySystemDao.performReindexingPass(100), greaterThan(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ITermCodeSystemDao myTermCodeSystemDao;
|
private ITermCodeSystemDao myTermCodeSystemDao;
|
||||||
|
|
||||||
|
@ -181,16 +51,16 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
|
||||||
TermConcept childAAA = new TermConcept(cs, "childAAA");
|
TermConcept childAAA = new TermConcept(cs, "childAAA");
|
||||||
childAAA.addPropertyString("propA", "valueAAA");
|
childAAA.addPropertyString("propA", "valueAAA");
|
||||||
childAAA.addPropertyString("propB", "foo");
|
childAAA.addPropertyString("propB", "foo");
|
||||||
childAAA.addDesignation()
|
|
||||||
.setUseSystem("http://designationsystem")
|
|
||||||
.setUseCode("somedesig")
|
|
||||||
.setUseDisplay("Designation Use")
|
|
||||||
.setValue("Bananas");
|
|
||||||
childAA.addChild(childAAA, RelationshipTypeEnum.ISA);
|
childAA.addChild(childAAA, RelationshipTypeEnum.ISA);
|
||||||
|
|
||||||
TermConcept childAAB = new TermConcept(cs, "childAAB");
|
TermConcept childAAB = new TermConcept(cs, "childAAB");
|
||||||
childAAB.addPropertyString("propA", "valueAAB");
|
childAAB.addPropertyString("propA", "valueAAB");
|
||||||
childAAB.addPropertyString("propB", "foo");
|
childAAB.addPropertyString("propB", "foo");
|
||||||
|
childAAB.addDesignation()
|
||||||
|
.setUseSystem("D1S")
|
||||||
|
.setUseCode("D1C")
|
||||||
|
.setUseDisplay("D1D")
|
||||||
|
.setValue("D1V");
|
||||||
childAA.addChild(childAAB, RelationshipTypeEnum.ISA);
|
childAA.addChild(childAAB, RelationshipTypeEnum.ISA);
|
||||||
|
|
||||||
TermConcept childAB = new TermConcept(cs, "childAB");
|
TermConcept childAB = new TermConcept(cs, "childAB");
|
||||||
|
@ -199,7 +69,7 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
|
||||||
TermConcept parentB = new TermConcept(cs, "ParentB");
|
TermConcept parentB = new TermConcept(cs, "ParentB");
|
||||||
cs.getConcepts().add(parentB);
|
cs.getConcepts().add(parentB);
|
||||||
|
|
||||||
myTermSvc.storeNewCodeSystemVersion(table.getId(), CS_URL,"SYSTEM NAME" , cs);
|
myTermSvc.storeNewCodeSystemVersion(table.getId(), CS_URL, "SYSTEM NAME", cs);
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
@ -218,30 +88,48 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
|
||||||
TermConcept parentA = new TermConcept(cs, "CS2");
|
TermConcept parentA = new TermConcept(cs, "CS2");
|
||||||
cs.getConcepts().add(parentA);
|
cs.getConcepts().add(parentA);
|
||||||
|
|
||||||
myTermSvc.storeNewCodeSystemVersion(table.getId(), CS_URL_2,"SYSTEM NAME" , cs);
|
myTermSvc.storeNewCodeSystemVersion(table.getId(), CS_URL_2, "SYSTEM NAME", cs);
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFindCodesAbove() {
|
public void testCreateDuplicateCodeSystemUri() {
|
||||||
IIdType id = createCodeSystem();
|
CodeSystem codeSystem = new CodeSystem();
|
||||||
|
codeSystem.setUrl(CS_URL);
|
||||||
|
codeSystem.setContent(CodeSystemContentMode.NOTPRESENT);
|
||||||
|
IIdType id = myCodeSystemDao.create(codeSystem, mySrd).getId().toUnqualified();
|
||||||
|
|
||||||
Set<TermConcept> concepts;
|
ResourceTable table = myResourceTableDao.findOne(id.getIdPartAsLong());
|
||||||
Set<String> codes;
|
|
||||||
|
|
||||||
concepts = myTermSvc.findCodesAbove(id.getIdPartAsLong(), id.getVersionIdPartAsLong(), "childAA");
|
TermCodeSystemVersion cs = new TermCodeSystemVersion();
|
||||||
codes = toCodes(concepts);
|
cs.setResource(table);
|
||||||
assertThat(codes, containsInAnyOrder("ParentA", "childAA"));
|
|
||||||
|
|
||||||
concepts = myTermSvc.findCodesAbove(id.getIdPartAsLong(), id.getVersionIdPartAsLong(), "childAAB");
|
myTermSvc.storeNewCodeSystemVersion(table.getId(), CS_URL, "SYSTEM NAME", cs);
|
||||||
codes = toCodes(concepts);
|
|
||||||
assertThat(codes, containsInAnyOrder("ParentA", "childAA", "childAAB"));
|
// Update
|
||||||
|
cs = new TermCodeSystemVersion();
|
||||||
|
TermConcept parentA = new TermConcept(cs, "ParentA");
|
||||||
|
cs.getConcepts().add(parentA);
|
||||||
|
id = myCodeSystemDao.update(codeSystem, null, true, true, mySrd).getId().toUnqualified();
|
||||||
|
table = myResourceTableDao.findOne(id.getIdPartAsLong());
|
||||||
|
cs.setResource(table);
|
||||||
|
myTermSvc.storeNewCodeSystemVersion(table.getId(), CS_URL, "SYSTEM NAME", cs);
|
||||||
|
|
||||||
|
// Try to update to a different resource
|
||||||
|
codeSystem = new CodeSystem();
|
||||||
|
codeSystem.setUrl(CS_URL);
|
||||||
|
codeSystem.setContent(CodeSystemContentMode.NOTPRESENT);
|
||||||
|
id = myCodeSystemDao.create(codeSystem, mySrd).getId().toUnqualified();
|
||||||
|
table = myResourceTableDao.findOne(id.getIdPartAsLong());
|
||||||
|
cs.setResource(table);
|
||||||
|
try {
|
||||||
|
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/"));
|
||||||
|
}
|
||||||
|
|
||||||
// Try an unknown code
|
|
||||||
concepts = myTermSvc.findCodesAbove(id.getIdPartAsLong(), id.getVersionIdPartAsLong(), "FOO_BAD_CODE");
|
|
||||||
codes = toCodes(concepts);
|
|
||||||
assertThat(codes, empty());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -310,18 +198,143 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
|
||||||
assertThat(codes, containsInAnyOrder("ParentA", "childAAA", "childAAB", "childAA", "childAB", "ParentB"));
|
assertThat(codes, containsInAnyOrder("ParentA", "childAAA", "childAAB", "childAA", "childAB", "ParentB"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<String> toCodesContains(List<ValueSet.ValueSetExpansionContainsComponent> theContains) {
|
@Test
|
||||||
List<String> retVal = new ArrayList<>();
|
public void testPropertiesAndDesignationsPreservedInExpansion() {
|
||||||
|
createCodeSystem();
|
||||||
|
|
||||||
for (ValueSet.ValueSetExpansionContainsComponent next : theContains) {
|
List<String> codes;
|
||||||
retVal.add(next.getCode());
|
|
||||||
}
|
|
||||||
|
|
||||||
return retVal;
|
ValueSet vs = new ValueSet();
|
||||||
|
ValueSet.ConceptSetComponent include = vs.getCompose().addInclude();
|
||||||
|
include.setSystem(CS_URL);
|
||||||
|
include.addConcept().setCode("childAAB");
|
||||||
|
ValueSet outcome = myTermSvc.expandValueSet(vs);
|
||||||
|
|
||||||
|
codes = toCodesContains(outcome.getExpansion().getContains());
|
||||||
|
assertThat(codes, containsInAnyOrder("childAAB"));
|
||||||
|
|
||||||
|
ValueSet.ValueSetExpansionContainsComponent concept = outcome.getExpansion().getContains().get(0);
|
||||||
|
assertEquals("childAAB", concept.getCode());
|
||||||
|
assertEquals("http://example.com/my_code_system", concept.getSystem());
|
||||||
|
assertEquals(null, concept.getDisplay());
|
||||||
|
assertEquals("D1S", concept.getDesignation().get(0).getUse().getSystem());
|
||||||
|
assertEquals("D1C", concept.getDesignation().get(0).getUse().getCode());
|
||||||
|
assertEquals("D1D", concept.getDesignation().get(0).getUse().getDisplay());
|
||||||
|
assertEquals("D1V", concept.getDesignation().get(0).getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCreateDuplicateCodeSystemUri() {
|
public void testFindCodesAbove() {
|
||||||
|
IIdType id = createCodeSystem();
|
||||||
|
|
||||||
|
Set<TermConcept> concepts;
|
||||||
|
Set<String> codes;
|
||||||
|
|
||||||
|
concepts = myTermSvc.findCodesAbove(id.getIdPartAsLong(), id.getVersionIdPartAsLong(), "childAA");
|
||||||
|
codes = toCodes(concepts);
|
||||||
|
assertThat(codes, containsInAnyOrder("ParentA", "childAA"));
|
||||||
|
|
||||||
|
concepts = myTermSvc.findCodesAbove(id.getIdPartAsLong(), id.getVersionIdPartAsLong(), "childAAB");
|
||||||
|
codes = toCodes(concepts);
|
||||||
|
assertThat(codes, containsInAnyOrder("ParentA", "childAA", "childAAB"));
|
||||||
|
|
||||||
|
// Try an unknown code
|
||||||
|
concepts = myTermSvc.findCodesAbove(id.getIdPartAsLong(), id.getVersionIdPartAsLong(), "FOO_BAD_CODE");
|
||||||
|
codes = toCodes(concepts);
|
||||||
|
assertThat(codes, empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFindCodesAboveAndBelowUnknown() {
|
||||||
|
createCodeSystem();
|
||||||
|
|
||||||
|
assertThat(myTermSvc.findCodesBelow("http://foo", "code"), empty());
|
||||||
|
assertThat(myTermSvc.findCodesBelow(CS_URL, "code"), empty());
|
||||||
|
assertThat(myTermSvc.findCodesAbove("http://foo", "code"), empty());
|
||||||
|
assertThat(myTermSvc.findCodesAbove(CS_URL, "code"), empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFindCodesAboveBuiltInCodeSystem() {
|
||||||
|
List<VersionIndependentConcept> concepts;
|
||||||
|
Set<String> codes;
|
||||||
|
|
||||||
|
concepts = myTermSvc.findCodesAbove("http://hl7.org/fhir/allergy-clinical-status", "active");
|
||||||
|
codes = toCodes(concepts);
|
||||||
|
assertThat(codes, containsInAnyOrder("active"));
|
||||||
|
|
||||||
|
concepts = myTermSvc.findCodesAbove("http://hl7.org/fhir/allergy-clinical-status", "resolved");
|
||||||
|
codes = toCodes(concepts);
|
||||||
|
assertThat(codes, containsInAnyOrder("inactive", "resolved"));
|
||||||
|
|
||||||
|
// Unknown code
|
||||||
|
concepts = myTermSvc.findCodesAbove("http://hl7.org/fhir/allergy-clinical-status", "FOO");
|
||||||
|
codes = toCodes(concepts);
|
||||||
|
assertThat(codes, empty());
|
||||||
|
|
||||||
|
// Unknown system
|
||||||
|
concepts = myTermSvc.findCodesAbove("http://hl7.org/fhir/allergy-clinical-status2222", "active");
|
||||||
|
codes = toCodes(concepts);
|
||||||
|
assertThat(codes, empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFindCodesBelowA() {
|
||||||
|
IIdType id = createCodeSystem();
|
||||||
|
|
||||||
|
Set<TermConcept> concepts;
|
||||||
|
Set<String> codes;
|
||||||
|
|
||||||
|
concepts = myTermSvc.findCodesBelow(id.getIdPartAsLong(), id.getVersionIdPartAsLong(), "ParentA");
|
||||||
|
codes = toCodes(concepts);
|
||||||
|
assertThat(codes, containsInAnyOrder("ParentA", "childAA", "childAAA", "childAAB", "childAB"));
|
||||||
|
|
||||||
|
concepts = myTermSvc.findCodesBelow(id.getIdPartAsLong(), id.getVersionIdPartAsLong(), "childAA");
|
||||||
|
codes = toCodes(concepts);
|
||||||
|
assertThat(codes, containsInAnyOrder("childAA", "childAAA", "childAAB"));
|
||||||
|
|
||||||
|
// Try an unknown code
|
||||||
|
concepts = myTermSvc.findCodesBelow(id.getIdPartAsLong(), id.getVersionIdPartAsLong(), "FOO_BAD_CODE");
|
||||||
|
codes = toCodes(concepts);
|
||||||
|
assertThat(codes, empty());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFindCodesBelowBuiltInCodeSystem() {
|
||||||
|
List<VersionIndependentConcept> concepts;
|
||||||
|
Set<String> codes;
|
||||||
|
|
||||||
|
concepts = myTermSvc.findCodesBelow("http://hl7.org/fhir/allergy-clinical-status", "inactive");
|
||||||
|
codes = toCodes(concepts);
|
||||||
|
assertThat(codes, containsInAnyOrder("inactive", "resolved"));
|
||||||
|
|
||||||
|
concepts = myTermSvc.findCodesBelow("http://hl7.org/fhir/allergy-clinical-status", "resolved");
|
||||||
|
codes = toCodes(concepts);
|
||||||
|
assertThat(codes, containsInAnyOrder("resolved"));
|
||||||
|
|
||||||
|
// Unknown code
|
||||||
|
concepts = myTermSvc.findCodesBelow("http://hl7.org/fhir/allergy-clinical-status", "FOO");
|
||||||
|
codes = toCodes(concepts);
|
||||||
|
assertThat(codes, empty());
|
||||||
|
|
||||||
|
// Unknown system
|
||||||
|
concepts = myTermSvc.findCodesBelow("http://hl7.org/fhir/allergy-clinical-status2222", "active");
|
||||||
|
codes = toCodes(concepts);
|
||||||
|
assertThat(codes, empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReindexTerminology() {
|
||||||
|
IIdType id = createCodeSystem();
|
||||||
|
|
||||||
|
assertThat(mySystemDao.markAllResourcesForReindexing(), greaterThan(0));
|
||||||
|
|
||||||
|
assertThat(mySystemDao.performReindexingPass(100), greaterThan(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStoreCodeSystemInvalidCyclicLoop() {
|
||||||
CodeSystem codeSystem = new CodeSystem();
|
CodeSystem codeSystem = new CodeSystem();
|
||||||
codeSystem.setUrl(CS_URL);
|
codeSystem.setUrl(CS_URL);
|
||||||
codeSystem.setContent(CodeSystemContentMode.NOTPRESENT);
|
codeSystem.setContent(CodeSystemContentMode.NOTPRESENT);
|
||||||
|
@ -332,31 +345,39 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
|
||||||
TermCodeSystemVersion cs = new TermCodeSystemVersion();
|
TermCodeSystemVersion cs = new TermCodeSystemVersion();
|
||||||
cs.setResource(table);
|
cs.setResource(table);
|
||||||
|
|
||||||
myTermSvc.storeNewCodeSystemVersion(table.getId(), CS_URL,"SYSTEM NAME" , cs);
|
TermConcept parent = new TermConcept();
|
||||||
|
parent.setCodeSystemVersion(cs);
|
||||||
|
parent.setCode("parent");
|
||||||
|
cs.getConcepts().add(parent);
|
||||||
|
|
||||||
// Update
|
TermConcept child = new TermConcept();
|
||||||
cs = new TermCodeSystemVersion();
|
child.setCodeSystemVersion(cs);
|
||||||
TermConcept parentA = new TermConcept(cs, "ParentA");
|
child.setCode("child");
|
||||||
cs.getConcepts().add(parentA);
|
parent.addChild(child, RelationshipTypeEnum.ISA);
|
||||||
id = myCodeSystemDao.update(codeSystem, null, true, true, mySrd).getId().toUnqualified();
|
|
||||||
table = myResourceTableDao.findOne(id.getIdPartAsLong());
|
child.addChild(parent, RelationshipTypeEnum.ISA);
|
||||||
cs.setResource(table);
|
|
||||||
myTermSvc.storeNewCodeSystemVersion(table.getId(), CS_URL,"SYSTEM NAME" , cs);
|
|
||||||
|
|
||||||
// Try to update to a different resource
|
|
||||||
codeSystem = new CodeSystem();
|
|
||||||
codeSystem.setUrl(CS_URL);
|
|
||||||
codeSystem.setContent(CodeSystemContentMode.NOTPRESENT);
|
|
||||||
id = myCodeSystemDao.create(codeSystem, mySrd).getId().toUnqualified();
|
|
||||||
table = myResourceTableDao.findOne(id.getIdPartAsLong());
|
|
||||||
cs.setResource(table);
|
|
||||||
try {
|
try {
|
||||||
myTermSvc.storeNewCodeSystemVersion(table.getId(), CS_URL,"SYSTEM NAME" , cs);
|
myTermSvc.storeNewCodeSystemVersion(table.getId(), "http://foo", "SYSTEM NAME", cs);
|
||||||
fail();
|
fail();
|
||||||
} catch (UnprocessableEntityException e) {
|
} catch (InvalidRequestException 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/"));
|
assertEquals("CodeSystem contains circular reference around code parent", e.getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<String> toCodesContains(List<ValueSet.ValueSetExpansionContainsComponent> theContains) {
|
||||||
|
List<String> retVal = new ArrayList<>();
|
||||||
|
|
||||||
|
for (ValueSet.ValueSetExpansionContainsComponent next : theContains) {
|
||||||
|
retVal.add(next.getCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void afterClassClearContext() {
|
||||||
|
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,9 +8,10 @@ import ca.uhn.fhir.jpa.provider.JpaConformanceProviderDstu2;
|
||||||
import ca.uhn.fhir.jpa.provider.JpaSystemProviderDstu2;
|
import ca.uhn.fhir.jpa.provider.JpaSystemProviderDstu2;
|
||||||
import ca.uhn.fhir.jpa.provider.dstu3.JpaConformanceProviderDstu3;
|
import ca.uhn.fhir.jpa.provider.dstu3.JpaConformanceProviderDstu3;
|
||||||
import ca.uhn.fhir.jpa.provider.dstu3.JpaSystemProviderDstu3;
|
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.JpaConformanceProviderR4;
|
||||||
import ca.uhn.fhir.jpa.provider.r4.JpaSystemProviderR4;
|
import ca.uhn.fhir.jpa.provider.r4.JpaSystemProviderR4;
|
||||||
import ca.uhn.fhir.jpa.provider.TerminologyUploaderProvider;
|
import ca.uhn.fhir.jpa.provider.r4.TerminologyUploaderProviderR4;
|
||||||
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
||||||
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
|
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
|
||||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||||
|
@ -50,6 +51,13 @@ public class TestRestfulServer extends RestfulServer {
|
||||||
|
|
||||||
private AnnotationConfigWebApplicationContext myAppCtx;
|
private AnnotationConfigWebApplicationContext myAppCtx;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy() {
|
||||||
|
super.destroy();
|
||||||
|
ourLog.info("Server is shutting down");
|
||||||
|
myAppCtx.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
protected void initialize() throws ServletException {
|
protected void initialize() throws ServletException {
|
||||||
|
@ -120,7 +128,7 @@ public class TestRestfulServer extends RestfulServer {
|
||||||
JpaConformanceProviderDstu3 confProvider = new JpaConformanceProviderDstu3(this, systemDao, myAppCtx.getBean(DaoConfig.class));
|
JpaConformanceProviderDstu3 confProvider = new JpaConformanceProviderDstu3(this, systemDao, myAppCtx.getBean(DaoConfig.class));
|
||||||
confProvider.setImplementationDescription(implDesc);
|
confProvider.setImplementationDescription(implDesc);
|
||||||
setServerConformanceProvider(confProvider);
|
setServerConformanceProvider(confProvider);
|
||||||
plainProviders.add(myAppCtx.getBean(TerminologyUploaderProvider.class));
|
plainProviders.add(myAppCtx.getBean(TerminologyUploaderProviderDstu3.class));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "R4": {
|
case "R4": {
|
||||||
|
@ -138,7 +146,7 @@ public class TestRestfulServer extends RestfulServer {
|
||||||
JpaConformanceProviderR4 confProvider = new JpaConformanceProviderR4(this, systemDao, myAppCtx.getBean(DaoConfig.class));
|
JpaConformanceProviderR4 confProvider = new JpaConformanceProviderR4(this, systemDao, myAppCtx.getBean(DaoConfig.class));
|
||||||
confProvider.setImplementationDescription(implDesc);
|
confProvider.setImplementationDescription(implDesc);
|
||||||
setServerConformanceProvider(confProvider);
|
setServerConformanceProvider(confProvider);
|
||||||
plainProviders.add(myAppCtx.getBean(TerminologyUploaderProvider.class));
|
plainProviders.add(myAppCtx.getBean(TerminologyUploaderProviderR4.class));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -226,13 +234,6 @@ public class TestRestfulServer extends RestfulServer {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void destroy() {
|
|
||||||
super.destroy();
|
|
||||||
ourLog.info("Server is shutting down");
|
|
||||||
myAppCtx.destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The public server is deployed to http://fhirtest.uhn.ca and the JEE webserver
|
* The public server is deployed to http://fhirtest.uhn.ca and the JEE webserver
|
||||||
* where this FHIR server is deployed is actually fronted by an Apache HTTPd instance,
|
* where this FHIR server is deployed is actually fronted by an Apache HTTPd instance,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package ca.uhn.fhirtest.interceptor;
|
package ca.uhn.fhirtest.interceptor;
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.provider.BaseJpaSystemProvider;
|
import ca.uhn.fhir.jpa.provider.BaseJpaSystemProvider;
|
||||||
import ca.uhn.fhir.jpa.provider.TerminologyUploaderProvider;
|
import ca.uhn.fhir.jpa.provider.BaseTerminologyUploaderProvider;
|
||||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.ForbiddenOperationException;
|
import ca.uhn.fhir.rest.server.exceptions.ForbiddenOperationException;
|
||||||
import ca.uhn.fhir.rest.server.interceptor.auth.AuthorizationInterceptor;
|
import ca.uhn.fhir.rest.server.interceptor.auth.AuthorizationInterceptor;
|
||||||
|
@ -16,8 +16,8 @@ import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||||
|
|
||||||
public class PublicSecurityInterceptor extends AuthorizationInterceptor {
|
public class PublicSecurityInterceptor extends AuthorizationInterceptor {
|
||||||
|
|
||||||
private HashSet<String> myTokens;
|
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(PublicSecurityInterceptor.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(PublicSecurityInterceptor.class);
|
||||||
|
private HashSet<String> myTokens;
|
||||||
|
|
||||||
public PublicSecurityInterceptor() {
|
public PublicSecurityInterceptor() {
|
||||||
String passwordsString = System.getProperty("fhir.tdlpass");
|
String passwordsString = System.getProperty("fhir.tdlpass");
|
||||||
|
@ -34,7 +34,7 @@ public class PublicSecurityInterceptor extends AuthorizationInterceptor {
|
||||||
if (isBlank(authHeader)) {
|
if (isBlank(authHeader)) {
|
||||||
return new RuleBuilder()
|
return new RuleBuilder()
|
||||||
.deny().operation().named(BaseJpaSystemProvider.MARK_ALL_RESOURCES_FOR_REINDEXING).onServer().andThen()
|
.deny().operation().named(BaseJpaSystemProvider.MARK_ALL_RESOURCES_FOR_REINDEXING).onServer().andThen()
|
||||||
.deny().operation().named(TerminologyUploaderProvider.UPLOAD_EXTERNAL_CODE_SYSTEM).onServer().andThen()
|
.deny().operation().named(BaseTerminologyUploaderProvider.UPLOAD_EXTERNAL_CODE_SYSTEM).onServer().andThen()
|
||||||
.allowAll()
|
.allowAll()
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
|
@ -279,8 +279,11 @@ public class RestfulServer extends HttpServlet implements IRestfulServer<Servlet
|
||||||
supertype = supertype.getSuperclass();
|
supertype = supertype.getSuperclass();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
count += findResourceMethods(theProvider, clazz);
|
count += findResourceMethods(theProvider, clazz);
|
||||||
|
} catch (ConfigurationException e) {
|
||||||
|
throw new ConfigurationException("Failure scanning class " + clazz.getSimpleName() + ": " + e.getMessage());
|
||||||
|
}
|
||||||
if (count == 0) {
|
if (count == 0) {
|
||||||
throw new ConfigurationException("Did not find any annotated RESTful methods on provider class " + theProvider.getClass().getCanonicalName());
|
throw new ConfigurationException("Did not find any annotated RESTful methods on provider class " + theProvider.getClass().getCanonicalName());
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
import static org.apache.commons.lang3.StringUtils.defaultString;
|
||||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
|
||||||
public class DefaultProfileValidationSupport implements IValidationSupport {
|
public class DefaultProfileValidationSupport implements IValidationSupport {
|
||||||
|
@ -33,19 +34,41 @@ public class DefaultProfileValidationSupport implements IValidationSupport {
|
||||||
private Map<String, StructureDefinition> myStructureDefinitions;
|
private Map<String, StructureDefinition> myStructureDefinitions;
|
||||||
private Map<String, ValueSet> myValueSets;
|
private Map<String, ValueSet> myValueSets;
|
||||||
|
|
||||||
|
private void addConcepts(ConceptSetComponent theInclude, ValueSetExpansionComponent theRetVal, Set<String> theWantCodes, List<ConceptDefinitionComponent> theConcepts) {
|
||||||
|
for (ConceptDefinitionComponent next : theConcepts) {
|
||||||
|
if (theWantCodes.isEmpty() || theWantCodes.contains(next.getCode())) {
|
||||||
|
theRetVal
|
||||||
|
.addContains()
|
||||||
|
.setSystem(theInclude.getSystem())
|
||||||
|
.setCode(next.getCode())
|
||||||
|
.setDisplay(next.getDisplay());
|
||||||
|
}
|
||||||
|
addConcepts(theInclude, theRetVal, theWantCodes, next.getConcept());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ValueSetExpansionComponent expandValueSet(FhirContext theContext, ConceptSetComponent theInclude) {
|
public ValueSetExpansionComponent expandValueSet(FhirContext theContext, ConceptSetComponent theInclude) {
|
||||||
ValueSetExpansionComponent retVal = new ValueSetExpansionComponent();
|
ValueSetExpansionComponent retVal = new ValueSetExpansionComponent();
|
||||||
|
|
||||||
Set<String> wantCodes = new HashSet<String>();
|
Set<String> wantCodes = new HashSet<>();
|
||||||
for (ConceptReferenceComponent next : theInclude.getConcept()) {
|
for (ConceptReferenceComponent next : theInclude.getConcept()) {
|
||||||
wantCodes.add(next.getCode());
|
wantCodes.add(next.getCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
CodeSystem system = fetchCodeSystem(theContext, theInclude.getSystem());
|
CodeSystem system = fetchCodeSystem(theContext, theInclude.getSystem());
|
||||||
for (ConceptDefinitionComponent next : system.getConcept()) {
|
if (system != null) {
|
||||||
if (wantCodes.isEmpty() || wantCodes.contains(next.getCode())) {
|
List<ConceptDefinitionComponent> concepts = system.getConcept();
|
||||||
retVal.addContains().setSystem(theInclude.getSystem()).setCode(next.getCode()).setDisplay(next.getDisplay());
|
addConcepts(theInclude, retVal, wantCodes, concepts);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (UriType next : theInclude.getValueSet()) {
|
||||||
|
ValueSet vs = myValueSets.get(defaultString(next.getValueAsString()));
|
||||||
|
if (vs != null) {
|
||||||
|
for (ConceptSetComponent nextInclude : vs.getCompose().getInclude()) {
|
||||||
|
ValueSetExpansionComponent contents = expandValueSet(theContext, nextInclude);
|
||||||
|
retVal.getContains().addAll(contents.getContains());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
import static org.apache.commons.lang3.StringUtils.defaultString;
|
||||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
|
||||||
public class DefaultProfileValidationSupport implements IValidationSupport {
|
public class DefaultProfileValidationSupport implements IValidationSupport {
|
||||||
|
@ -44,15 +45,37 @@ public class DefaultProfileValidationSupport implements IValidationSupport {
|
||||||
}
|
}
|
||||||
|
|
||||||
CodeSystem system = fetchCodeSystem(theContext, theInclude.getSystem());
|
CodeSystem system = fetchCodeSystem(theContext, theInclude.getSystem());
|
||||||
for (ConceptDefinitionComponent next : system.getConcept()) {
|
if (system != null) {
|
||||||
if (wantCodes.isEmpty() || wantCodes.contains(next.getCode())) {
|
List<ConceptDefinitionComponent> concepts = system.getConcept();
|
||||||
retVal.addContains().setSystem(theInclude.getSystem()).setCode(next.getCode()).setDisplay(next.getDisplay());
|
addConcepts(theInclude, retVal, wantCodes, concepts);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (UriType next: theInclude.getValueSet()) {
|
||||||
|
ValueSet vs = myValueSets.get(defaultString(next.getValueAsString()));
|
||||||
|
if (vs != null) {
|
||||||
|
for (ConceptSetComponent nextInclude : vs.getCompose().getInclude()) {
|
||||||
|
ValueSetExpansionComponent contents = expandValueSet(theContext, nextInclude);
|
||||||
|
retVal.getContains().addAll(contents.getContains());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addConcepts(ConceptSetComponent theInclude, ValueSetExpansionComponent theRetVal, Set<String> theWantCodes, List<ConceptDefinitionComponent> theConcepts) {
|
||||||
|
for (ConceptDefinitionComponent next : theConcepts) {
|
||||||
|
if (theWantCodes.isEmpty() || theWantCodes.contains(next.getCode())) {
|
||||||
|
theRetVal
|
||||||
|
.addContains()
|
||||||
|
.setSystem(theInclude.getSystem())
|
||||||
|
.setCode(next.getCode())
|
||||||
|
.setDisplay(next.getDisplay());
|
||||||
|
}
|
||||||
|
addConcepts(theInclude, theRetVal, theWantCodes, next.getConcept());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<IBaseResource> fetchAllConformanceResources(FhirContext theContext) {
|
public List<IBaseResource> fetchAllConformanceResources(FhirContext theContext) {
|
||||||
ArrayList<IBaseResource> retVal = new ArrayList<>();
|
ArrayList<IBaseResource> retVal = new ArrayList<>();
|
||||||
|
|
|
@ -4,6 +4,7 @@ import ca.uhn.fhir.context.FhirContext;
|
||||||
import org.hl7.fhir.dstu3.hapi.ctx.IValidationSupport;
|
import org.hl7.fhir.dstu3.hapi.ctx.IValidationSupport;
|
||||||
import org.hl7.fhir.dstu3.model.CodeSystem;
|
import org.hl7.fhir.dstu3.model.CodeSystem;
|
||||||
import org.hl7.fhir.dstu3.model.StructureDefinition;
|
import org.hl7.fhir.dstu3.model.StructureDefinition;
|
||||||
|
import org.hl7.fhir.dstu3.model.UriType;
|
||||||
import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent;
|
import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent;
|
||||||
import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionComponent;
|
import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionComponent;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
@ -14,6 +15,7 @@ import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||||
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
|
||||||
public class ValidationSupportChain implements IValidationSupport {
|
public class ValidationSupportChain implements IValidationSupport {
|
||||||
|
|
||||||
|
@ -47,10 +49,18 @@ public class ValidationSupportChain implements IValidationSupport {
|
||||||
@Override
|
@Override
|
||||||
public ValueSetExpansionComponent expandValueSet(FhirContext theCtx, ConceptSetComponent theInclude) {
|
public ValueSetExpansionComponent expandValueSet(FhirContext theCtx, ConceptSetComponent theInclude) {
|
||||||
for (IValidationSupport next : myChain) {
|
for (IValidationSupport next : myChain) {
|
||||||
|
if (isNotBlank(theInclude.getSystem())) {
|
||||||
if (next.isCodeSystemSupported(theCtx, theInclude.getSystem())) {
|
if (next.isCodeSystemSupported(theCtx, theInclude.getSystem())) {
|
||||||
return next.expandValueSet(theCtx, theInclude);
|
return next.expandValueSet(theCtx, theInclude);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (UriType nextValueSet : theInclude.getValueSet()) {
|
||||||
|
ValueSetExpansionComponent retVal = next.expandValueSet(theCtx, theInclude);
|
||||||
|
if (retVal != null && retVal.getContains().size() > 0) {
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return myChain.get(0).expandValueSet(theCtx, theInclude);
|
return myChain.get(0).expandValueSet(theCtx, theInclude);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue