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.jpa.dao.DaoConfig;
|
||||
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.JpaSystemProviderDstu3;
|
||||
import ca.uhn.fhir.jpa.provider.dstu3.TerminologyUploaderProviderDstu3;
|
||||
import ca.uhn.fhir.jpa.rp.dstu3.ActivityDefinitionResourceProvider;
|
||||
import ca.uhn.fhir.jpa.rp.dstu3.MeasureResourceProvider;
|
||||
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
|
||||
* with this feature.
|
||||
*/
|
||||
registerProvider(myAppCtx.getBean(TerminologyUploaderProvider.class));
|
||||
registerProvider(myAppCtx.getBean(TerminologyUploaderProviderDstu3.class));
|
||||
}
|
||||
|
||||
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.dstu3.JpaConformanceProviderDstu3;
|
||||
import ca.uhn.fhir.jpa.provider.dstu3.JpaSystemProviderDstu3;
|
||||
import ca.uhn.fhir.jpa.provider.dstu3.TerminologyUploaderProviderDstu3;
|
||||
import ca.uhn.fhir.jpa.provider.r4.JpaConformanceProviderR4;
|
||||
import ca.uhn.fhir.jpa.provider.r4.JpaSystemProviderR4;
|
||||
import ca.uhn.fhir.jpa.provider.TerminologyUploaderProvider;
|
||||
import ca.uhn.fhir.jpa.provider.r4.TerminologyUploaderProviderR4;
|
||||
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Bundle;
|
||||
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
|
||||
|
@ -78,10 +79,10 @@ public class JpaServerDemo extends RestfulServer {
|
|||
systemProvider.add(myAppCtx.getBean("mySystemProviderDstu2", JpaSystemProviderDstu2.class));
|
||||
} else if (fhirVersion == FhirVersionEnum.DSTU3) {
|
||||
systemProvider.add(myAppCtx.getBean("mySystemProviderDstu3", JpaSystemProviderDstu3.class));
|
||||
systemProvider.add(myAppCtx.getBean(TerminologyUploaderProvider.class));
|
||||
systemProvider.add(myAppCtx.getBean(TerminologyUploaderProviderDstu3.class));
|
||||
} else if (fhirVersion == FhirVersionEnum.R4) {
|
||||
systemProvider.add(myAppCtx.getBean("mySystemProviderR4", JpaSystemProviderR4.class));
|
||||
systemProvider.add(myAppCtx.getBean(TerminologyUploaderProvider.class));
|
||||
systemProvider.add(myAppCtx.getBean(TerminologyUploaderProviderR4.class));
|
||||
} else {
|
||||
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.dstu3.SearchParamExtractorDstu3;
|
||||
import ca.uhn.fhir.jpa.dao.dstu3.SearchParamRegistryDstu3;
|
||||
import ca.uhn.fhir.jpa.provider.TerminologyUploaderProvider;
|
||||
import ca.uhn.fhir.jpa.term.*;
|
||||
import ca.uhn.fhir.jpa.provider.dstu3.TerminologyUploaderProviderDstu3;
|
||||
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.validation.IValidatorModule;
|
||||
import org.hl7.fhir.dstu3.hapi.ctx.IValidationSupport;
|
||||
|
@ -115,8 +118,8 @@ public class BaseDstu3Config extends BaseConfig {
|
|||
}
|
||||
|
||||
@Bean(autowire = Autowire.BY_TYPE)
|
||||
public TerminologyUploaderProvider terminologyUploaderProvider() {
|
||||
TerminologyUploaderProvider retVal = new TerminologyUploaderProvider();
|
||||
public TerminologyUploaderProviderDstu3 terminologyUploaderProvider() {
|
||||
TerminologyUploaderProviderDstu3 retVal = new TerminologyUploaderProviderDstu3();
|
||||
retVal.setContext(fhirContextDstu3());
|
||||
return retVal;
|
||||
}
|
||||
|
@ -126,5 +129,5 @@ public class BaseDstu3Config extends BaseConfig {
|
|||
public IValidationSupport validationSupportChainDstu3() {
|
||||
return new JpaValidationSupportChainDstu3();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ import ca.uhn.fhir.jpa.dao.ISearchParamRegistry;
|
|||
import ca.uhn.fhir.jpa.dao.r4.SearchParamExtractorR4;
|
||||
import ca.uhn.fhir.jpa.dao.r4.SearchParamRegistryR4;
|
||||
import ca.uhn.fhir.jpa.graphql.JpaStorageServices;
|
||||
import ca.uhn.fhir.jpa.provider.TerminologyUploaderProvider;
|
||||
import ca.uhn.fhir.jpa.provider.r4.TerminologyUploaderProviderR4;
|
||||
import ca.uhn.fhir.jpa.term.HapiTerminologySvcR4;
|
||||
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
|
||||
import ca.uhn.fhir.jpa.term.IHapiTerminologySvcR4;
|
||||
|
@ -133,8 +133,8 @@ public class BaseR4Config extends BaseConfig {
|
|||
}
|
||||
|
||||
@Bean(autowire = Autowire.BY_TYPE)
|
||||
public TerminologyUploaderProvider terminologyUploaderProvider() {
|
||||
TerminologyUploaderProvider retVal = new TerminologyUploaderProvider();
|
||||
public TerminologyUploaderProviderR4 terminologyUploaderProvider() {
|
||||
TerminologyUploaderProviderR4 retVal = new TerminologyUploaderProviderR4();
|
||||
retVal.setContext(fhirContextR4());
|
||||
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.RestSearchParameterTypeEnum;
|
||||
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.server.exceptions.*;
|
||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||
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.util.*;
|
||||
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.Bundle.HTTPVerb;
|
||||
import org.hl7.fhir.r4.model.CanonicalType;
|
||||
import org.hl7.fhir.r4.model.IdType;
|
||||
import org.hl7.fhir.r4.model.Reference;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
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 String PROCESSING_SUB_REQUEST = "BaseHapiFhirDao.processingSubRequest";
|
||||
private static boolean ourValidationDisabledForUnitTest;
|
||||
private static boolean ourDisableIncrementOnUpdateForUnitTest = false;
|
||||
|
||||
static {
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
public void injectDependenciesIntoBundleProvider(PersistedJpaBundleProvider theProvider) {
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
if (theElement == null) {
|
||||
return;
|
||||
|
@ -2133,6 +2200,11 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
return b.toString();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public static void setDisableIncrementOnUpdateForUnitTest(boolean theDisableIncrementOnUpdateForUnitTest) {
|
||||
ourDisableIncrementOnUpdateForUnitTest = theDisableIncrementOnUpdateForUnitTest;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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> {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseHapiFhirResourceDao.class);
|
||||
private static boolean ourDisableIncrementOnUpdateForUnitTest = false;
|
||||
@Autowired
|
||||
protected PlatformTransactionManager myPlatformTransactionManager;
|
||||
@Autowired
|
||||
|
@ -592,22 +591,6 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
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) {
|
||||
if (theRequestDetails == null || theRequestDetails.getServer() == null) {
|
||||
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() + "]");
|
||||
}
|
||||
|
||||
// Notify interceptors
|
||||
ActionRequestDetails requestDetails = null;
|
||||
if (theRequestDetails != null) {
|
||||
requestDetails = new ActionRequestDetails(theRequestDetails, theResource, getResourceName(), resourceId);
|
||||
notifyInterceptors(RestOperationTypeEnum.UPDATE, requestDetails);
|
||||
}
|
||||
|
||||
IBaseResource oldResource = toResource(entity, false);
|
||||
|
||||
// Notify IServerOperationInterceptors about pre-action call
|
||||
if (theRequestDetails != null) {
|
||||
theRequestDetails.getRequestOperationCallback().resourcePreUpdate(oldResource, theResource);
|
||||
/*
|
||||
* If we aren't indexing, that means we're doing this inside a transaction.
|
||||
* 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),
|
||||
* 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
|
||||
* Otherwise, we're not in a transaction
|
||||
*/
|
||||
if (!thePerformIndexing && !savedEntity.isUnchangedInCurrentOperation() && !ourDisableIncrementOnUpdateForUnitTest) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ResourceTable savedEntity = updateInternal(theResource, thePerformIndexing, theForceUpdateVersion, theRequestDetails, entity, resourceId, oldResource);
|
||||
DaoMethodOutcome outcome = toMethodOutcome(savedEntity, theResource).setCreated(false);
|
||||
|
||||
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.rest.api.MethodOutcome;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
||||
public class DaoMethodOutcome extends MethodOutcome {
|
||||
|
||||
private ResourceTable myEntity;
|
||||
private IBaseResource myPreviousResource;
|
||||
|
||||
public ResourceTable getEntity() {
|
||||
return myEntity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DaoMethodOutcome setCreated(Boolean theCreated) {
|
||||
super.setCreated(theCreated);
|
||||
return this;
|
||||
}
|
||||
|
||||
public DaoMethodOutcome setEntity(ResourceTable theEntity) {
|
||||
myEntity = theEntity;
|
||||
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.
|
||||
* #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.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.EntryResponse;
|
||||
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.InstantDt;
|
||||
import ca.uhn.fhir.model.primitive.UriDt;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
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.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.method.BaseMethodBinding;
|
||||
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.UrlUtil;
|
||||
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> {
|
||||
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;
|
||||
ourLog.info("Batch completed in {}ms", new Object[] { delay });
|
||||
ourLog.info("Batch completed in {}ms", new Object[] {delay});
|
||||
|
||||
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")
|
||||
private Bundle doTransaction(ServletRequestDetails theRequestDetails, Bundle theRequest, String theActionName) {
|
||||
BundleTypeEnum transactionType = theRequest.getTypeElement().getValueAsEnum();
|
||||
|
@ -279,10 +176,10 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle, MetaDt> {
|
|||
|
||||
/*
|
||||
* We want to execute the transaction request bundle elements in the order
|
||||
* specified by the FHIR specification (see TransactionSorter) so we save the
|
||||
* specified by the FHIR specification (see TransactionSorter) so we save the
|
||||
* original order in the request, then sort it.
|
||||
*
|
||||
* Entries with a type of GET are removed from the bundle so that they
|
||||
*
|
||||
* Entries with a type of GET are removed from the bundle so that they
|
||||
* can be processed at the very end. We do this because the incoming resources
|
||||
* are saved in a two-phase way in order to deal with interdependencies, and
|
||||
* we want the GET processing to use the final indexing state
|
||||
|
@ -298,11 +195,12 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle, MetaDt> {
|
|||
}
|
||||
}
|
||||
Collections.sort(theRequest.getEntry(), new TransactionSorter());
|
||||
|
||||
List<IIdType> deletedResources = new ArrayList<IIdType>();
|
||||
List<DeleteConflict> deleteConflicts = new ArrayList<DeleteConflict>();
|
||||
Map<Entry, ResourceTable> entriesToProcess = new IdentityHashMap<Entry, ResourceTable>();
|
||||
|
||||
List<IIdType> deletedResources = new ArrayList<>();
|
||||
List<DeleteConflict> deleteConflicts = new ArrayList<>();
|
||||
Map<Entry, ResourceTable> entriesToProcess = new IdentityHashMap<>();
|
||||
Set<ResourceTable> nonUpdatedEntities = new HashSet<ResourceTable>();
|
||||
Set<ResourceTable> updatedEntities = new HashSet<>();
|
||||
|
||||
/*
|
||||
* Loop through the request and process any entries of type
|
||||
|
@ -321,7 +219,7 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle, MetaDt> {
|
|||
|
||||
nextResourceId = res.getId();
|
||||
|
||||
if (nextResourceId.hasIdPart() == false) {
|
||||
if (!nextResourceId.hasIdPart()) {
|
||||
if (isNotBlank(nextReqEntry.getFullUrl())) {
|
||||
nextResourceId = new IdDt(nextReqEntry.getFullUrl());
|
||||
}
|
||||
|
@ -361,86 +259,85 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle, MetaDt> {
|
|||
Entry nextRespEntry = response.getEntry().get(originalRequestOrder.get(nextReqEntry));
|
||||
|
||||
switch (verb) {
|
||||
case POST: {
|
||||
// CREATE
|
||||
@SuppressWarnings("rawtypes")
|
||||
IFhirResourceDao resourceDao = getDaoOrThrowException(res.getClass());
|
||||
res.setId((String) null);
|
||||
DaoMethodOutcome outcome;
|
||||
outcome = resourceDao.create(res, nextReqEntry.getRequest().getIfNoneExist(), false, theRequestDetails);
|
||||
handleTransactionCreateOrUpdateOutcome(idSubstitutions, idToPersistedOutcome, nextResourceId, outcome, nextRespEntry, resourceType, res);
|
||||
entriesToProcess.put(nextRespEntry, outcome.getEntity());
|
||||
if (outcome.getCreated() == false) {
|
||||
nonUpdatedEntities.add(outcome.getEntity());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DELETE: {
|
||||
// DELETE
|
||||
String url = extractTransactionUrlOrThrowException(nextReqEntry, verb);
|
||||
UrlParts parts = UrlUtil.parseUrl(url);
|
||||
ca.uhn.fhir.jpa.dao.IFhirResourceDao<? extends IBaseResource> dao = toDao(parts, verb.getCode(), url);
|
||||
int status = Constants.STATUS_HTTP_204_NO_CONTENT;
|
||||
if (parts.getResourceId() != null) {
|
||||
DaoMethodOutcome outcome = dao.delete(new IdDt(parts.getResourceType(), parts.getResourceId()), deleteConflicts, theRequestDetails);
|
||||
if (outcome.getEntity() != null) {
|
||||
deletedResources.add(outcome.getId().toUnqualifiedVersionless());
|
||||
entriesToProcess.put(nextRespEntry, outcome.getEntity());
|
||||
}
|
||||
} else {
|
||||
DeleteMethodOutcome deleteOutcome = dao.deleteByUrl(parts.getResourceType() + '?' + parts.getParams(), deleteConflicts, theRequestDetails);
|
||||
List<ResourceTable> allDeleted = deleteOutcome.getDeletedEntities();
|
||||
for (ResourceTable deleted : allDeleted) {
|
||||
deletedResources.add(deleted.getIdDt().toUnqualifiedVersionless());
|
||||
}
|
||||
if (allDeleted.isEmpty()) {
|
||||
status = Constants.STATUS_HTTP_404_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
nextRespEntry.getResponse().setStatus(toStatusString(status));
|
||||
break;
|
||||
}
|
||||
case PUT: {
|
||||
// UPDATE
|
||||
@SuppressWarnings("rawtypes")
|
||||
IFhirResourceDao resourceDao = getDaoOrThrowException(res.getClass());
|
||||
|
||||
DaoMethodOutcome outcome;
|
||||
|
||||
String url = extractTransactionUrlOrThrowException(nextReqEntry, verb);
|
||||
|
||||
UrlParts parts = UrlUtil.parseUrl(url);
|
||||
if (isNotBlank(parts.getResourceId())) {
|
||||
res.setId(new IdDt(parts.getResourceType(), parts.getResourceId()));
|
||||
outcome = resourceDao.update(res, null, false, theRequestDetails);
|
||||
} else {
|
||||
case POST: {
|
||||
// CREATE
|
||||
@SuppressWarnings("rawtypes")
|
||||
IFhirResourceDao resourceDao = getDaoOrThrowException(res.getClass());
|
||||
res.setId((String) null);
|
||||
outcome = resourceDao.update(res, parts.getResourceType() + '?' + parts.getParams(), false, theRequestDetails);
|
||||
DaoMethodOutcome outcome;
|
||||
outcome = resourceDao.create(res, nextReqEntry.getRequest().getIfNoneExist(), false, theRequestDetails);
|
||||
handleTransactionCreateOrUpdateOutcome(idSubstitutions, idToPersistedOutcome, nextResourceId, outcome, nextRespEntry, resourceType, res);
|
||||
entriesToProcess.put(nextRespEntry, outcome.getEntity());
|
||||
if (outcome.getCreated() == false) {
|
||||
nonUpdatedEntities.add(outcome.getEntity());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DELETE: {
|
||||
// DELETE
|
||||
String url = extractTransactionUrlOrThrowException(nextReqEntry, verb);
|
||||
UrlParts parts = UrlUtil.parseUrl(url);
|
||||
ca.uhn.fhir.jpa.dao.IFhirResourceDao<? extends IBaseResource> dao = toDao(parts, verb.getCode(), url);
|
||||
int status = Constants.STATUS_HTTP_204_NO_CONTENT;
|
||||
if (parts.getResourceId() != null) {
|
||||
DaoMethodOutcome outcome = dao.delete(new IdDt(parts.getResourceType(), parts.getResourceId()), deleteConflicts, theRequestDetails);
|
||||
if (outcome.getEntity() != null) {
|
||||
deletedResources.add(outcome.getId().toUnqualifiedVersionless());
|
||||
entriesToProcess.put(nextRespEntry, outcome.getEntity());
|
||||
}
|
||||
} else {
|
||||
DeleteMethodOutcome deleteOutcome = dao.deleteByUrl(parts.getResourceType() + '?' + parts.getParams(), deleteConflicts, theRequestDetails);
|
||||
List<ResourceTable> allDeleted = deleteOutcome.getDeletedEntities();
|
||||
for (ResourceTable deleted : allDeleted) {
|
||||
deletedResources.add(deleted.getIdDt().toUnqualifiedVersionless());
|
||||
}
|
||||
if (allDeleted.isEmpty()) {
|
||||
status = Constants.STATUS_HTTP_404_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
handleTransactionCreateOrUpdateOutcome(idSubstitutions, idToPersistedOutcome, nextResourceId, outcome, nextRespEntry, resourceType, res);
|
||||
entriesToProcess.put(nextRespEntry, outcome.getEntity());
|
||||
break;
|
||||
}
|
||||
case GET:
|
||||
break;
|
||||
nextRespEntry.getResponse().setStatus(toStatusString(status));
|
||||
break;
|
||||
}
|
||||
case PUT: {
|
||||
// UPDATE
|
||||
@SuppressWarnings("rawtypes")
|
||||
IFhirResourceDao resourceDao = getDaoOrThrowException(res.getClass());
|
||||
|
||||
DaoMethodOutcome outcome;
|
||||
|
||||
String url = extractTransactionUrlOrThrowException(nextReqEntry, verb);
|
||||
|
||||
UrlParts parts = UrlUtil.parseUrl(url);
|
||||
if (isNotBlank(parts.getResourceId())) {
|
||||
res.setId(new IdDt(parts.getResourceType(), parts.getResourceId()));
|
||||
outcome = resourceDao.update(res, null, false, theRequestDetails);
|
||||
} else {
|
||||
res.setId((String) null);
|
||||
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);
|
||||
entriesToProcess.put(nextRespEntry, outcome.getEntity());
|
||||
break;
|
||||
}
|
||||
case GET:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure that there are no conflicts from deletions. E.g. we can't delete something
|
||||
* if something else has a reference to it.. Unless the thing that has a reference to it
|
||||
* was also deleted as a part of this transaction, which is why we check this now at the
|
||||
* was also deleted as a part of this transaction, which is why we check this now at the
|
||||
* end.
|
||||
*/
|
||||
|
||||
for (Iterator<DeleteConflict> iter = deleteConflicts.iterator(); iter.hasNext(); ) {
|
||||
DeleteConflict next = iter.next();
|
||||
if (deletedResources.contains(next.getTargetId().toVersionless())) {
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
|
||||
deleteConflicts.removeIf(next -> deletedResources.contains(next.getTargetId().toVersionless()));
|
||||
validateDeleteConflictsEmptyOrThrowException(deleteConflicts);
|
||||
|
||||
/*
|
||||
|
@ -489,8 +386,9 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle, MetaDt> {
|
|||
|
||||
InstantDt deletedInstantOrNull = ResourceMetadataKeyEnum.DELETED_AT.get(nextResource);
|
||||
Date deletedTimestampOrNull = deletedInstantOrNull != null ? deletedInstantOrNull.getValue() : null;
|
||||
boolean shouldUpdate = !nonUpdatedEntities.contains(nextOutcome.getEntity());
|
||||
if (shouldUpdate) {
|
||||
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, updateTime, false, true);
|
||||
}
|
||||
}
|
||||
|
@ -508,7 +406,7 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle, MetaDt> {
|
|||
Set<Long> val = resourceDao.processMatchUrl(matchUrl);
|
||||
if (val.size() > 1) {
|
||||
throw new InvalidRequestException(
|
||||
"Unable to process " + theActionName + " - Request would cause multiple resources to match URL: \"" + matchUrl + "\". Does transaction request contain duplicates?");
|
||||
"Unable to process " + theActionName + " - Request would cause multiple resources to match URL: \"" + matchUrl + "\". Does transaction request contain duplicates?");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -537,9 +435,9 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle, MetaDt> {
|
|||
requestDetails.setServletRequest(theRequestDetails.getServletRequest());
|
||||
requestDetails.setRequestType(RequestTypeEnum.GET);
|
||||
requestDetails.setServer(theRequestDetails.getServer());
|
||||
|
||||
|
||||
String url = extractTransactionUrlOrThrowException(nextReqEntry, HTTPVerbEnum.GET);
|
||||
|
||||
|
||||
int qIndex = url.indexOf('?');
|
||||
ArrayListMultimap<String, String> paramValues = ArrayListMultimap.create();
|
||||
requestDetails.setParameters(new HashMap<String, String[]>());
|
||||
|
@ -564,7 +462,7 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle, MetaDt> {
|
|||
if (method == null) {
|
||||
throw new IllegalArgumentException("Unable to handle GET " + url);
|
||||
}
|
||||
|
||||
|
||||
if (isNotBlank(nextReqEntry.getRequest().getIfMatch())) {
|
||||
requestDetails.addHeader(Constants.HEADER_IF_MATCH, nextReqEntry.getRequest().getIfMatch());
|
||||
}
|
||||
|
@ -574,7 +472,7 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle, MetaDt> {
|
|||
if (isNotBlank(nextReqEntry.getRequest().getIfNoneMatch())) {
|
||||
requestDetails.addHeader(Constants.HEADER_IF_NONE_MATCH, nextReqEntry.getRequest().getIfNoneMatch());
|
||||
}
|
||||
|
||||
|
||||
if (method instanceof BaseResourceReturningMethodBinding) {
|
||||
try {
|
||||
IBaseResource resource = ((BaseResourceReturningMethodBinding) method).doInvokeServer(theRequestDetails.getServer(), requestDetails);
|
||||
|
@ -594,23 +492,132 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle, MetaDt> {
|
|||
|
||||
ourLog.info("Flushing context after {}", theActionName);
|
||||
myEntityManager.flush();
|
||||
|
||||
|
||||
for (java.util.Map.Entry<Entry, ResourceTable> nextEntry : entriesToProcess.entrySet()) {
|
||||
nextEntry.getKey().getResponse().setLocation(nextEntry.getValue().getIdDt().toUnqualified().getValue());
|
||||
nextEntry.getKey().getResponse().setEtag(nextEntry.getValue().getIdDt().getVersionIdPart());
|
||||
}
|
||||
|
||||
|
||||
long delay = System.currentTimeMillis() - start;
|
||||
int numEntries = theRequest.getEntry().size();
|
||||
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);
|
||||
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,
|
||||
Entry newEntry, String theResourceType, IResource theRes) {
|
||||
Entry newEntry, String theResourceType, IResource theRes) {
|
||||
IdDt newId = (IdDt) outcome.getId().toUnqualifiedVersionless();
|
||||
IdDt resourceId = isPlaceholder(nextResourceId) ? nextResourceId : nextResourceId.toUnqualifiedVersionless();
|
||||
if (newId.equals(resourceId) == false) {
|
||||
|
@ -645,9 +652,10 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle, MetaDt> {
|
|||
}
|
||||
|
||||
//@formatter:off
|
||||
|
||||
/**
|
||||
* Transaction Order, per the spec:
|
||||
*
|
||||
* <p>
|
||||
* Process any DELETE interactions
|
||||
* Process any POST interactions
|
||||
* Process any PUT interactions
|
||||
|
@ -657,7 +665,7 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle, MetaDt> {
|
|||
public class TransactionSorter implements Comparator<Entry> {
|
||||
|
||||
@Override
|
||||
public int compare(Entry theO1, Entry theO2) {
|
||||
public int compare(Entry theO1, Entry theO2) {
|
||||
int o1 = toOrder(theO1);
|
||||
int o2 = toOrder(theO2);
|
||||
|
||||
|
@ -667,20 +675,20 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle, MetaDt> {
|
|||
private int toOrder(Entry theO1) {
|
||||
int o1 = 0;
|
||||
if (theO1.getRequest().getMethodElement().getValueAsEnum() != null) {
|
||||
switch (theO1.getRequest().getMethodElement().getValueAsEnum()) {
|
||||
case DELETE:
|
||||
o1 = 1;
|
||||
break;
|
||||
case POST:
|
||||
o1 = 2;
|
||||
break;
|
||||
case PUT:
|
||||
o1 = 3;
|
||||
break;
|
||||
case GET:
|
||||
o1 = 4;
|
||||
break;
|
||||
}
|
||||
switch (theO1.getRequest().getMethodElement().getValueAsEnum()) {
|
||||
case DELETE:
|
||||
o1 = 1;
|
||||
break;
|
||||
case POST:
|
||||
o1 = 2;
|
||||
break;
|
||||
case PUT:
|
||||
o1 = 3;
|
||||
break;
|
||||
case GET:
|
||||
o1 = 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return o1;
|
||||
}
|
||||
|
|
|
@ -1193,7 +1193,7 @@ public class SearchBuilder implements ISearchBuilder {
|
|||
codes = myTerminologySvc.findCodesBelow(system, code);
|
||||
}
|
||||
|
||||
ArrayList<Predicate> singleCodePredicates = new ArrayList<Predicate>();
|
||||
ArrayList<Predicate> singleCodePredicates = new ArrayList<>();
|
||||
if (codes != null) {
|
||||
|
||||
if (codes.isEmpty()) {
|
||||
|
@ -1581,7 +1581,8 @@ public class SearchBuilder implements ISearchBuilder {
|
|||
}
|
||||
}
|
||||
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) {
|
||||
if (nextCandidate.getCode().equals(code)) {
|
||||
retVal = nextCandidate.getSystem();
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
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;
|
||||
|
||||
/*
|
||||
|
@ -22,17 +29,15 @@ import java.util.List;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
public interface ITermCodeSystemVersionDao extends JpaRepository<TermCodeSystemVersion, Long> {
|
||||
|
||||
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
||||
|
||||
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")
|
||||
List<TermCodeSystemVersion> findByCodeSystemResource(@Param("resource_id") Long theCodeSystemResourcePid);
|
||||
|
||||
|
||||
@Query("SELECT cs FROM TermCodeSystemVersion cs WHERE cs.myCodeSystemHavingThisVersionAsCurrentVersionIfAny.myResource.myId = :resource_id")
|
||||
TermCodeSystemVersion findCurrentVersionForCodeSystemResourcePid(@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")
|
||||
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
|
||||
void deleteByCodeSystemVersion(@Param("cs_pid") Long thePid);
|
||||
List<TermConcept> findByCodeSystemVersion(@Param("cs_pid") Long thePid);
|
||||
|
||||
@Query("UPDATE TermConcept t SET t.myIndexStatus = null")
|
||||
@Modifying
|
||||
|
|
|
@ -158,13 +158,11 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
|||
|
||||
ourLog.debug("Beginning {} with {} resources", theActionName, theRequest.getEntry().size());
|
||||
|
||||
// long start = System.currentTimeMillis();
|
||||
final StopWatch transactionSw = new StopWatch();
|
||||
final Date updateTime = new Date();
|
||||
|
||||
final Set<IdType> allIds = new LinkedHashSet<IdType>();
|
||||
final Map<IdType, IdType> idSubstitutions = new HashMap<IdType, IdType>();
|
||||
final Map<IdType, DaoMethodOutcome> idToPersistedOutcome = new HashMap<IdType, DaoMethodOutcome>();
|
||||
final Set<IdType> allIds = new LinkedHashSet<>();
|
||||
final Map<IdType, IdType> idSubstitutions = new HashMap<>();
|
||||
final Map<IdType, DaoMethodOutcome> idToPersistedOutcome = new HashMap<>();
|
||||
|
||||
// Do all entries have a verb?
|
||||
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>>() {
|
||||
@Override
|
||||
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()) {
|
||||
|
@ -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);
|
||||
return response;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Map<BundleEntryComponent, ResourceTable> doTransactionWriteOperations(ServletRequestDetails theRequestDetails, Bundle theRequest, String theActionName, Date updateTime, Set<IdType> allIds,
|
||||
Map<IdType, IdType> theIdSubstitutions, Map<IdType, DaoMethodOutcome> idToPersistedOutcome, Bundle response, IdentityHashMap<BundleEntryComponent, Integer> originalRequestOrder, List<BundleEntryComponent> theEntries, StopWatch theStopWatch) {
|
||||
|
||||
private Map<BundleEntryComponent, ResourceTable> doTransactionWriteOperations(ServletRequestDetails theRequestDetails, Bundle theRequest, String theActionName, Date theUpdateTime, Set<IdType> theAllIds,
|
||||
Map<IdType, IdType> theIdSubstitutions, Map<IdType, DaoMethodOutcome> theIdToPersistedOutcome, Bundle theResponse, IdentityHashMap<BundleEntryComponent, Integer> theOriginalRequestOrder, List<BundleEntryComponent> theEntries) {
|
||||
Set<String> deletedResources = new HashSet<>();
|
||||
List<DeleteConflict> deleteConflicts = new ArrayList<>();
|
||||
Map<BundleEntryComponent, ResourceTable> entriesToProcess = new IdentityHashMap<>();
|
||||
Set<ResourceTable> nonUpdatedEntities = new HashSet<>();
|
||||
Set<ResourceTable> updatedEntities = new HashSet<>();
|
||||
Map<String, Class<? extends IBaseResource>> conditionalRequestUrls = new HashMap<>();
|
||||
|
||||
/*
|
||||
|
@ -333,7 +328,7 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
|||
|
||||
nextResourceId = res.getIdElement();
|
||||
|
||||
if (nextResourceId.hasIdPart() == false) {
|
||||
if (!nextResourceId.hasIdPart()) {
|
||||
if (isNotBlank(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
|
||||
*/
|
||||
if (isPlaceholder(nextResourceId)) {
|
||||
if (!allIds.add(nextResourceId)) {
|
||||
if (!theAllIds.add(nextResourceId)) {
|
||||
throw new InvalidRequestException(getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionContainsMultipleWithDuplicateId", nextResourceId));
|
||||
}
|
||||
} else if (nextResourceId.hasResourceType() && nextResourceId.hasIdPart()) {
|
||||
IdType nextId = nextResourceId.toUnqualifiedVersionless();
|
||||
if (!allIds.add(nextId)) {
|
||||
if (!theAllIds.add(nextId)) {
|
||||
throw new InvalidRequestException(getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionContainsMultipleWithDuplicateId", nextId));
|
||||
}
|
||||
}
|
||||
|
@ -367,111 +362,112 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
|||
HTTPVerb verb = nextReqEntry.getRequest().getMethodElement().getValue();
|
||||
|
||||
String resourceType = res != null ? getContext().getResourceDefinition(res).getName() : null;
|
||||
BundleEntryComponent nextRespEntry = response.getEntry().get(originalRequestOrder.get(nextReqEntry));
|
||||
|
||||
theStopWatch.startTask("Process entry " + i + ": " + verb + " " + defaultString(resourceType));
|
||||
BundleEntryComponent nextRespEntry = theResponse.getEntry().get(theOriginalRequestOrder.get(nextReqEntry));
|
||||
|
||||
switch (verb) {
|
||||
case POST: {
|
||||
// CREATE
|
||||
@SuppressWarnings("rawtypes")
|
||||
IFhirResourceDao resourceDao = getDaoOrThrowException(res.getClass());
|
||||
res.setId((String) null);
|
||||
DaoMethodOutcome outcome;
|
||||
String matchUrl = nextReqEntry.getRequest().getIfNoneExist();
|
||||
matchUrl = performIdSubstitutionsInMatchUrl(theIdSubstitutions, matchUrl);
|
||||
outcome = resourceDao.create(res, matchUrl, false, theRequestDetails);
|
||||
if (nextResourceId != null) {
|
||||
handleTransactionCreateOrUpdateOutcome(theIdSubstitutions, idToPersistedOutcome, nextResourceId, outcome, nextRespEntry, resourceType, res, theRequestDetails);
|
||||
}
|
||||
entriesToProcess.put(nextRespEntry, outcome.getEntity());
|
||||
if (outcome.getCreated() == false) {
|
||||
nonUpdatedEntities.add(outcome.getEntity());
|
||||
} else {
|
||||
if (isNotBlank(matchUrl)) {
|
||||
conditionalRequestUrls.put(matchUrl, res.getClass());
|
||||
case POST: {
|
||||
// CREATE
|
||||
@SuppressWarnings("rawtypes")
|
||||
IFhirResourceDao resourceDao = getDaoOrThrowException(res.getClass());
|
||||
res.setId((String) null);
|
||||
DaoMethodOutcome outcome;
|
||||
String matchUrl = nextReqEntry.getRequest().getIfNoneExist();
|
||||
matchUrl = performIdSubstitutionsInMatchUrl(theIdSubstitutions, matchUrl);
|
||||
outcome = resourceDao.create(res, matchUrl, false, theRequestDetails);
|
||||
if (nextResourceId != null) {
|
||||
handleTransactionCreateOrUpdateOutcome(theIdSubstitutions, theIdToPersistedOutcome, nextResourceId, outcome, nextRespEntry, resourceType, res, theRequestDetails);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case DELETE: {
|
||||
// DELETE
|
||||
String url = extractTransactionUrlOrThrowException(nextReqEntry, verb);
|
||||
UrlParts parts = UrlUtil.parseUrl(url);
|
||||
ca.uhn.fhir.jpa.dao.IFhirResourceDao<? extends IBaseResource> dao = toDao(parts, verb.toCode(), url);
|
||||
int status = Constants.STATUS_HTTP_204_NO_CONTENT;
|
||||
if (parts.getResourceId() != null) {
|
||||
IdType deleteId = new IdType(parts.getResourceType(), parts.getResourceId());
|
||||
if (!deletedResources.contains(deleteId.getValueAsString())) {
|
||||
DaoMethodOutcome outcome = dao.delete(deleteId, deleteConflicts, theRequestDetails);
|
||||
if (outcome.getEntity() != null) {
|
||||
deletedResources.add(deleteId.getValueAsString());
|
||||
entriesToProcess.put(nextRespEntry, outcome.getEntity());
|
||||
entriesToProcess.put(nextRespEntry, outcome.getEntity());
|
||||
if (outcome.getCreated() == false) {
|
||||
nonUpdatedEntities.add(outcome.getEntity());
|
||||
} else {
|
||||
if (isNotBlank(matchUrl)) {
|
||||
conditionalRequestUrls.put(matchUrl, res.getClass());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
String matchUrl = parts.getResourceType() + '?' + parts.getParams();
|
||||
matchUrl = performIdSubstitutionsInMatchUrl(theIdSubstitutions, matchUrl);
|
||||
DeleteMethodOutcome deleteOutcome = dao.deleteByUrl(matchUrl, deleteConflicts, theRequestDetails);
|
||||
List<ResourceTable> allDeleted = deleteOutcome.getDeletedEntities();
|
||||
for (ResourceTable deleted : allDeleted) {
|
||||
deletedResources.add(deleted.getIdDt().toUnqualifiedVersionless().getValueAsString());
|
||||
}
|
||||
if (allDeleted.isEmpty()) {
|
||||
status = Constants.STATUS_HTTP_204_NO_CONTENT;
|
||||
}
|
||||
|
||||
nextRespEntry.getResponse().setOutcome((Resource) deleteOutcome.getOperationOutcome());
|
||||
break;
|
||||
}
|
||||
|
||||
nextRespEntry.getResponse().setStatus(toStatusString(status));
|
||||
|
||||
break;
|
||||
}
|
||||
case PUT: {
|
||||
// UPDATE
|
||||
@SuppressWarnings("rawtypes")
|
||||
IFhirResourceDao resourceDao = getDaoOrThrowException(res.getClass());
|
||||
|
||||
String url = extractTransactionUrlOrThrowException(nextReqEntry, verb);
|
||||
|
||||
DaoMethodOutcome outcome;
|
||||
UrlParts parts = UrlUtil.parseUrl(url);
|
||||
if (isNotBlank(parts.getResourceId())) {
|
||||
String version = null;
|
||||
if (isNotBlank(nextReqEntry.getRequest().getIfMatch())) {
|
||||
version = ParameterUtil.parseETagValue(nextReqEntry.getRequest().getIfMatch());
|
||||
}
|
||||
res.setId(new IdType(parts.getResourceType(), parts.getResourceId(), version));
|
||||
outcome = resourceDao.update(res, null, false, theRequestDetails);
|
||||
} else {
|
||||
res.setId((String) null);
|
||||
String matchUrl;
|
||||
if (isNotBlank(parts.getParams())) {
|
||||
matchUrl = parts.getResourceType() + '?' + parts.getParams();
|
||||
case DELETE: {
|
||||
// DELETE
|
||||
String url = extractTransactionUrlOrThrowException(nextReqEntry, verb);
|
||||
UrlParts parts = UrlUtil.parseUrl(url);
|
||||
ca.uhn.fhir.jpa.dao.IFhirResourceDao<? extends IBaseResource> dao = toDao(parts, verb.toCode(), url);
|
||||
int status = Constants.STATUS_HTTP_204_NO_CONTENT;
|
||||
if (parts.getResourceId() != null) {
|
||||
IdType deleteId = new IdType(parts.getResourceType(), parts.getResourceId());
|
||||
if (!deletedResources.contains(deleteId.getValueAsString())) {
|
||||
DaoMethodOutcome outcome = dao.delete(deleteId, deleteConflicts, theRequestDetails);
|
||||
if (outcome.getEntity() != null) {
|
||||
deletedResources.add(deleteId.getValueAsString());
|
||||
entriesToProcess.put(nextRespEntry, outcome.getEntity());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
matchUrl = parts.getResourceType();
|
||||
}
|
||||
matchUrl = performIdSubstitutionsInMatchUrl(theIdSubstitutions, matchUrl);
|
||||
outcome = resourceDao.update(res, matchUrl, false, theRequestDetails);
|
||||
if (Boolean.TRUE.equals(outcome.getCreated())) {
|
||||
conditionalRequestUrls.put(matchUrl, res.getClass());
|
||||
}
|
||||
}
|
||||
String matchUrl = parts.getResourceType() + '?' + parts.getParams();
|
||||
matchUrl = performIdSubstitutionsInMatchUrl(theIdSubstitutions, matchUrl);
|
||||
DeleteMethodOutcome deleteOutcome = dao.deleteByUrl(matchUrl, deleteConflicts, theRequestDetails);
|
||||
List<ResourceTable> allDeleted = deleteOutcome.getDeletedEntities();
|
||||
for (ResourceTable deleted : allDeleted) {
|
||||
deletedResources.add(deleted.getIdDt().toUnqualifiedVersionless().getValueAsString());
|
||||
}
|
||||
if (allDeleted.isEmpty()) {
|
||||
status = Constants.STATUS_HTTP_204_NO_CONTENT;
|
||||
}
|
||||
|
||||
nextRespEntry.getResponse().setOutcome((Resource) deleteOutcome.getOperationOutcome());
|
||||
}
|
||||
|
||||
nextRespEntry.getResponse().setStatus(toStatusString(status));
|
||||
|
||||
break;
|
||||
}
|
||||
case PUT: {
|
||||
// UPDATE
|
||||
@SuppressWarnings("rawtypes")
|
||||
IFhirResourceDao resourceDao = getDaoOrThrowException(res.getClass());
|
||||
|
||||
String url = extractTransactionUrlOrThrowException(nextReqEntry, verb);
|
||||
|
||||
DaoMethodOutcome outcome;
|
||||
UrlParts parts = UrlUtil.parseUrl(url);
|
||||
if (isNotBlank(parts.getResourceId())) {
|
||||
String version = null;
|
||||
if (isNotBlank(nextReqEntry.getRequest().getIfMatch())) {
|
||||
version = ParameterUtil.parseETagValue(nextReqEntry.getRequest().getIfMatch());
|
||||
}
|
||||
res.setId(new IdType(parts.getResourceType(), parts.getResourceId(), version));
|
||||
outcome = resourceDao.update(res, null, false, theRequestDetails);
|
||||
} else {
|
||||
res.setId((String) null);
|
||||
String matchUrl;
|
||||
if (isNotBlank(parts.getParams())) {
|
||||
matchUrl = parts.getResourceType() + '?' + parts.getParams();
|
||||
} else {
|
||||
matchUrl = parts.getResourceType();
|
||||
}
|
||||
matchUrl = performIdSubstitutionsInMatchUrl(theIdSubstitutions, matchUrl);
|
||||
outcome = resourceDao.update(res, matchUrl, false, theRequestDetails);
|
||||
if (Boolean.TRUE.equals(outcome.getCreated())) {
|
||||
conditionalRequestUrls.put(matchUrl, res.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
if (outcome.getCreated() == Boolean.FALSE) {
|
||||
updatedEntities.add(outcome.getEntity());
|
||||
}
|
||||
|
||||
handleTransactionCreateOrUpdateOutcome(theIdSubstitutions, theIdToPersistedOutcome, nextResourceId, outcome, nextRespEntry, resourceType, res, theRequestDetails);
|
||||
entriesToProcess.put(nextRespEntry, outcome.getEntity());
|
||||
break;
|
||||
}
|
||||
case GET:
|
||||
case NULL:
|
||||
break;
|
||||
|
||||
handleTransactionCreateOrUpdateOutcome(theIdSubstitutions, idToPersistedOutcome, nextResourceId, outcome, nextRespEntry, resourceType, res, theRequestDetails);
|
||||
entriesToProcess.put(nextRespEntry, outcome.getEntity());
|
||||
break;
|
||||
}
|
||||
case GET:
|
||||
case NULL:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
theStopWatch.endCurrentTask();
|
||||
|
||||
/*
|
||||
* Make sure that there are no conflicts from deletions. E.g. we can't delete something
|
||||
* if something else has a reference to it.. Unless the thing that has a reference to it
|
||||
|
@ -479,12 +475,8 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
|||
* end.
|
||||
*/
|
||||
|
||||
for (Iterator<DeleteConflict> iter = deleteConflicts.iterator(); iter.hasNext();) {
|
||||
DeleteConflict next = iter.next();
|
||||
if (deletedResources.contains(next.getTargetId().toUnqualifiedVersionless().getValue())) {
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
deleteConflicts.removeIf(next ->
|
||||
deletedResources.contains(next.getTargetId().toUnqualifiedVersionless().getValue()));
|
||||
validateDeleteConflictsEmptyOrThrowException(deleteConflicts);
|
||||
|
||||
/*
|
||||
|
@ -492,13 +484,13 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
|||
*/
|
||||
|
||||
FhirTerser terser = getContext().newTerser();
|
||||
for (DaoMethodOutcome nextOutcome : idToPersistedOutcome.values()) {
|
||||
for (DaoMethodOutcome nextOutcome : theIdToPersistedOutcome.values()) {
|
||||
IBaseResource nextResource = nextOutcome.getResource();
|
||||
if (nextResource == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Refererences
|
||||
// References
|
||||
List<IBaseReference> allRefs = terser.getAllPopulatedChildElementsOfType(nextResource, IBaseReference.class);
|
||||
for (IBaseReference nextRef : allRefs) {
|
||||
IIdType nextId = nextRef.getReferenceElement();
|
||||
|
@ -534,18 +526,16 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
|||
|
||||
IPrimitiveType<Date> deletedInstantOrNull = ResourceMetadataKeyEnum.DELETED_AT.get((IAnyResource) nextResource);
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
theStopWatch.startTask("Flush Session");
|
||||
|
||||
flushJpaSession();
|
||||
|
||||
theStopWatch.endCurrentTask();
|
||||
|
||||
/*
|
||||
* Double check we didn't allow any duplicates we shouldn't have
|
||||
*/
|
||||
|
@ -557,12 +547,12 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
|||
Set<Long> val = resourceDao.processMatchUrl(matchUrl);
|
||||
if (val.size() > 1) {
|
||||
throw new InvalidRequestException(
|
||||
"Unable to process " + theActionName + " - Request would cause multiple resources to match URL: \"" + matchUrl + "\". Does transaction request contain duplicates?");
|
||||
"Unable to process " + theActionName + " - Request would cause multiple resources to match URL: \"" + matchUrl + "\". Does transaction request contain duplicates?");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (IdType next : allIds) {
|
||||
for (IdType next : theAllIds) {
|
||||
IdType replacement = theIdSubstitutions.get(next);
|
||||
if (replacement == null) {
|
||||
continue;
|
||||
|
|
|
@ -19,6 +19,8 @@ import javax.transaction.Transactional.TxType;
|
|||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
|
@ -87,6 +89,9 @@ public class JpaValidationSupportDstu3 implements IJpaValidationSupportDstu3 {
|
|||
|
||||
@Override
|
||||
public CodeSystem fetchCodeSystem(FhirContext theCtx, String theSystem) {
|
||||
if (isBlank(theSystem)) {
|
||||
return null;
|
||||
}
|
||||
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.provider.ServletSubRequestDetails;
|
||||
import ca.uhn.fhir.jpa.util.DeleteConflict;
|
||||
import ca.uhn.fhir.util.StopWatch;
|
||||
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
import ca.uhn.fhir.parser.IParser;
|
||||
|
@ -266,7 +265,7 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
|||
paramValues.put(next.getName(), next.getValue());
|
||||
}
|
||||
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);
|
||||
}
|
||||
url = url.substring(0, qIndex);
|
||||
|
@ -323,6 +322,7 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
|||
List<DeleteConflict> deleteConflicts = new ArrayList<>();
|
||||
Map<BundleEntryComponent, ResourceTable> entriesToProcess = new IdentityHashMap<>();
|
||||
Set<ResourceTable> nonUpdatedEntities = new HashSet<>();
|
||||
Set<ResourceTable> updatedEntities = new HashSet<>();
|
||||
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);
|
||||
entriesToProcess.put(nextRespEntry, outcome.getEntity());
|
||||
break;
|
||||
|
@ -538,9 +542,11 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
|||
|
||||
IPrimitiveType<Date> deletedInstantOrNull = ResourceMetadataKeyEnum.DELETED_AT.get((IAnyResource) nextResource);
|
||||
Date deletedTimestampOrNull = deletedInstantOrNull != null ? deletedInstantOrNull.getValue() : null;
|
||||
boolean shouldUpdate = !nonUpdatedEntities.contains(nextOutcome.getEntity());
|
||||
if (shouldUpdate) {
|
||||
updateEntity(nextResource, nextOutcome.getEntity(), deletedTimestampOrNull, shouldUpdate, false, theUpdateTime, false, true);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ public abstract class BaseResourceIndexedSearchParam implements Serializable {
|
|||
private Long myResourcePid;
|
||||
|
||||
@Field()
|
||||
@Column(name = "RES_TYPE", nullable = false, length = 30)
|
||||
@Column(name = "RES_TYPE", nullable = false)
|
||||
private String myResourceType;
|
||||
|
||||
@Field()
|
||||
|
|
|
@ -20,6 +20,9 @@ package ca.uhn.fhir.jpa.entity;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.io.Serializable;
|
||||
|
||||
|
@ -89,4 +92,15 @@ public class TermCodeSystem implements Serializable {
|
|||
public void setResource(ResourceTable 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.
|
||||
*/
|
||||
@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;
|
||||
@SuppressWarnings("unused")
|
||||
@OneToOne(mappedBy = "myCurrentVersion", optional = true)
|
||||
|
|
|
@ -31,7 +31,7 @@ public class TermConceptDesignation implements Serializable {
|
|||
|
||||
private static final long serialVersionUID = 1L;
|
||||
@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;
|
||||
@Id()
|
||||
@SequenceGenerator(name = "SEQ_CONCEPT_DESIG_PID", sequenceName = "SEQ_CONCEPT_DESIG_PID")
|
||||
|
|
|
@ -1,5 +1,25 @@
|
|||
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.hibernate.search.bridge.FieldBridge;
|
||||
import org.hibernate.search.bridge.LuceneOptions;
|
||||
|
|
|
@ -1,5 +1,25 @@
|
|||
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#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.UploadStatistics;
|
||||
import ca.uhn.fhir.rest.annotation.Operation;
|
||||
import ca.uhn.fhir.rest.annotation.OperationParam;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import 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.Parameters;
|
||||
import org.hl7.fhir.r4.model.StringType;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.InputStream;
|
||||
import java.io.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.defaultString;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.*;
|
||||
|
||||
public class TerminologyUploaderProvider extends BaseJpaProvider {
|
||||
public abstract class BaseTerminologyUploaderProvider extends BaseJpaProvider {
|
||||
public static final String UPLOAD_EXTERNAL_CODE_SYSTEM = "$upload-external-code-system";
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TerminologyUploaderProvider.class);
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseTerminologyUploaderProvider.class);
|
||||
|
||||
@Autowired
|
||||
private IHapiTerminologyLoaderSvc myTerminologyLoaderSvc;
|
||||
|
||||
@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,
|
||||
RequestDetails theRequestDetails
|
||||
) {
|
||||
|
||||
protected Parameters handleUploadExternalCodeSystem(
|
||||
HttpServletRequest theServletRequest,
|
||||
StringParam theCodeSystemUrl,
|
||||
List<StringType> theLocalFile,
|
||||
List<Attachment> thePackage, RequestDetails theRequestDetails
|
||||
) {
|
||||
|
||||
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 {
|
||||
List<IHapiTerminologyLoaderSvc.FileDescriptor> localFiles = new ArrayList<>();
|
||||
if (theLocalFile != null && theLocalFile.size() > 0) {
|
||||
|
@ -70,8 +70,8 @@ public class TerminologyUploaderProvider extends BaseJpaProvider {
|
|||
if (isNotBlank(nextLocalFile.getValue())) {
|
||||
ourLog.info("Reading in local file: {}", nextLocalFile.getValue());
|
||||
File nextFile = new File(nextLocalFile.getValue());
|
||||
if (!nextFile.exists() || nextFile.isFile()) {
|
||||
throw new InvalidRequestException("Unknown file: " +nextFile.getName());
|
||||
if (!nextFile.exists() || !nextFile.isFile()) {
|
||||
throw new InvalidRequestException("Unknown file: " + nextFile.getName());
|
||||
}
|
||||
localFiles.add(new IHapiTerminologyLoaderSvc.FileDescriptor() {
|
||||
@Override
|
||||
|
@ -91,7 +91,27 @@ 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;
|
||||
url = defaultString(url);
|
||||
|
||||
|
@ -99,11 +119,11 @@ public class TerminologyUploaderProvider extends BaseJpaProvider {
|
|||
if (IHapiTerminologyLoaderSvc.SCT_URI.equals(url)) {
|
||||
stats = myTerminologyLoaderSvc.loadSnomedCt(localFiles, theRequestDetails);
|
||||
} else if (IHapiTerminologyLoaderSvc.LOINC_URI.equals(url)) {
|
||||
stats = myTerminologyLoaderSvc.loadLoinc(localFiles, theRequestDetails);
|
||||
stats = myTerminologyLoaderSvc.loadLoinc(localFiles, theRequestDetails);
|
||||
} else {
|
||||
throw new InvalidRequestException("Unknown URL: " + url);
|
||||
}
|
||||
|
||||
|
||||
Parameters retVal = new Parameters();
|
||||
retVal.addParameter().setName("conceptCount").setValue(new IntegerType(stats.getConceptCount()));
|
||||
return retVal;
|
||||
|
@ -112,5 +132,5 @@ public class TerminologyUploaderProvider extends BaseJpaProvider {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -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.setSystem(theCodeSystem);
|
||||
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;
|
||||
TermConcept code = findCode(system, nextCode);
|
||||
if (code != null) {
|
||||
addedCodes.add(nextCode);
|
||||
ValueSet.ValueSetExpansionContainsComponent contains = expansionComponent.addContains();
|
||||
contains.setCode(nextCode);
|
||||
contains.setSystem(system);
|
||||
contains.setDisplay(code.getDisplay());
|
||||
addCodeIfNotAlreadyAdded(system, expansionComponent, addedCodes, code);
|
||||
//
|
||||
// addedCodes.add(nextCode);
|
||||
// ValueSet.ValueSetExpansionContainsComponent contains = expansionComponent.addContains();
|
||||
// contains.setCode(nextCode);
|
||||
// contains.setSystem(system);
|
||||
// contains.setDisplay(code.getDisplay());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,6 +76,11 @@ public class HapiTerminologySvcDstu2 extends BaseHapiTerminologySvcImpl {
|
|||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CodeSystem getCodeSystemFromContext(String theSystem) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<VersionIndependentConcept> expandValueSet(String theValueSet) {
|
||||
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
|
||||
public List<IBaseResource> fetchAllConformanceResources(FhirContext theContext) {
|
||||
return null;
|
||||
|
@ -222,6 +240,16 @@ public class HapiTerminologySvcDstu3 extends BaseHapiTerminologySvcImpl implemen
|
|||
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
|
||||
public boolean isCodeSystemSupported(FhirContext theContext, String theSystem) {
|
||||
return myTerminologySvc.supportsSystem(theSystem);
|
||||
|
|
|
@ -112,6 +112,16 @@ public class HapiTerminologySvcR4 extends BaseHapiTerminologySvcImpl implements
|
|||
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
|
||||
public ValueSetExpansionComponent expandValueSet(FhirContext theContext, ConceptSetComponent theInclude) {
|
||||
ValueSet valueSetToExpand = new ValueSet();
|
||||
|
@ -188,6 +198,11 @@ public class HapiTerminologySvcR4 extends BaseHapiTerminologySvcImpl implements
|
|||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CodeSystem getCodeSystemFromContext(String theSystem) {
|
||||
return myValidationSupport.fetchCodeSystem(myContext, theSystem);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCodeSystemSupported(FhirContext theContext, String theSystem) {
|
||||
return myTerminologySvc.supportsSystem(theSystem);
|
||||
|
|
|
@ -1,5 +1,25 @@
|
|||
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;
|
||||
|
||||
public interface IRecordHandler {
|
||||
|
|
|
@ -128,6 +128,13 @@ public class TerminologyLoaderSvcImpl implements IHapiTerminologyLoaderSvc {
|
|||
CSVParser parsed;
|
||||
try {
|
||||
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();
|
||||
if (theQuoteMode != null) {
|
||||
format = format.withQuote('"').withQuoteMode(theQuoteMode);
|
||||
|
@ -402,16 +409,15 @@ public class TerminologyLoaderSvcImpl implements IHapiTerminologyLoaderSvc {
|
|||
LoadedFileDescriptors(List<IHapiTerminologyLoaderSvc.FileDescriptor> theFileDescriptors) {
|
||||
try {
|
||||
for (FileDescriptor next : theFileDescriptors) {
|
||||
File nextTemporaryFile = File.createTempFile("hapifhir", ".tmp");
|
||||
nextTemporaryFile.deleteOnExit();
|
||||
|
||||
if (next.getFilename().toLowerCase().endsWith(".zip")) {
|
||||
ourLog.info("Uncompressing {} into temporary files", next.getFilename());
|
||||
try (InputStream inputStream = next.getInputStream()) {
|
||||
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(inputStream));
|
||||
for (ZipEntry nextEntry; (nextEntry = zis.getNextEntry()) != null; ) {
|
||||
BOMInputStream fis = new BOMInputStream(zis);
|
||||
FileOutputStream fos = new FileOutputStream(nextTemporaryFile);
|
||||
File nextTemporaryFile = File.createTempFile("hapifhir", ".tmp");
|
||||
nextTemporaryFile.deleteOnExit();
|
||||
FileOutputStream fos = new FileOutputStream(nextTemporaryFile, false);
|
||||
IOUtils.copy(fis, fos);
|
||||
String nextEntryFileName = nextEntry.getName();
|
||||
myUncompressedFileDescriptors.add(new FileDescriptor() {
|
||||
|
|
|
@ -25,6 +25,16 @@ public class VersionIndependentConcept {
|
|||
private String mySystem;
|
||||
private String myCode;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public VersionIndependentConcept() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public VersionIndependentConcept(String theSystem, String theCode) {
|
||||
setSystem(theSystem);
|
||||
setCode(theCode);
|
||||
|
@ -34,16 +44,18 @@ public class VersionIndependentConcept {
|
|||
return mySystem;
|
||||
}
|
||||
|
||||
public void setSystem(String theSystem) {
|
||||
public VersionIndependentConcept setSystem(String theSystem) {
|
||||
mySystem = theSystem;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return myCode;
|
||||
}
|
||||
|
||||
public void setCode(String theCode) {
|
||||
public VersionIndependentConcept setCode(String theCode) {
|
||||
myCode = theCode;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,25 @@
|
|||
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.term.IRecordHandler;
|
||||
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())) {
|
||||
return;
|
||||
}
|
||||
|
@ -86,6 +106,7 @@ abstract class BaseHandler implements IRecordHandler {
|
|||
.addTelecom()
|
||||
.setSystem(ContactPoint.ContactPointSystem.URL)
|
||||
.setValue("https://loinc.org");
|
||||
conceptMap.setCopyright(theCopyright);
|
||||
myIdToConceptMaps.put(theMapping.getConceptMapId(), conceptMap);
|
||||
myConceptMaps.add(conceptMap);
|
||||
} else {
|
||||
|
@ -151,12 +172,13 @@ abstract class BaseHandler implements IRecordHandler {
|
|||
vs.setId(theValueSetId);
|
||||
vs.setName(theValueSetName);
|
||||
vs.setStatus(Enumerations.PublicationStatus.ACTIVE);
|
||||
vs.setPublisher("Regentrief Institute, Inc.");
|
||||
vs.setPublisher("Regenstrief Institute, Inc.");
|
||||
vs.addContact()
|
||||
.setName("Regentrief Institute, Inc.")
|
||||
.setName("Regenstrief Institute, Inc.")
|
||||
.addTelecom()
|
||||
.setSystem(ContactPoint.ContactPointSystem.URL)
|
||||
.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);
|
||||
myValueSets.add(vs);
|
||||
} else {
|
||||
|
|
|
@ -1,5 +1,25 @@
|
|||
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.term.IHapiTerminologyLoaderSvc;
|
||||
import ca.uhn.fhir.jpa.term.IRecordHandler;
|
||||
|
|
|
@ -1,5 +1,25 @@
|
|||
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.TermConcept;
|
||||
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
|
||||
|
|
|
@ -1,5 +1,25 @@
|
|||
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.TermConcept;
|
||||
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
|
||||
|
|
|
@ -1,5 +1,25 @@
|
|||
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.TermConcept;
|
||||
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 static final String DOCUMENT_ONTOLOGY_CODES_VS_ID = "DOCUMENT-ONTOLOGY-CODES-VS";
|
||||
public static final String DOCUMENT_ONTOLOGY_CODES_VS_URI = "http://loinc.org/document-ontology-codes";
|
||||
public static final String DOCUMENT_ONTOLOGY_CODES_VS_ID = "loinc-document-ontology";
|
||||
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";
|
||||
private final Map<String, TermConcept> myCode2Concept;
|
||||
private final TermCodeSystemVersion myCodeSystemVersion;
|
||||
|
|
|
@ -1,5 +1,25 @@
|
|||
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.TermConcept;
|
||||
import ca.uhn.fhir.jpa.term.IRecordHandler;
|
||||
|
@ -37,6 +57,13 @@ public class LoincHandler implements IRecordHandler {
|
|||
TermConcept concept = new TermConcept(myCodeSystemVersion, code);
|
||||
concept.setDisplay(display);
|
||||
|
||||
if (!display.equalsIgnoreCase(shortName)) {
|
||||
concept
|
||||
.addDesignation()
|
||||
.setUseDisplay("ShortName")
|
||||
.setValue(shortName);
|
||||
}
|
||||
|
||||
for (String nextPropertyName : myPropertyNames) {
|
||||
if (!theRecord.toMap().containsKey(nextPropertyName)) {
|
||||
continue;
|
||||
|
|
|
@ -1,5 +1,25 @@
|
|||
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.TermConcept;
|
||||
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink;
|
||||
|
|
|
@ -1,5 +1,25 @@
|
|||
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.term.IHapiTerminologyLoaderSvc;
|
||||
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_URI = "http://loinc.org/fhir/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
|
||||
|
@ -48,7 +69,8 @@ public class LoincIeeeMedicalDeviceCodeHandler extends BaseHandler implements IR
|
|||
.setTargetCodeSystem(targetCodeSystemUri)
|
||||
.setTargetCode(ieeeCode)
|
||||
.setTargetDisplay(ieeeDisplayName)
|
||||
.setEquivalence(Enumerations.ConceptMapEquivalence.EQUAL));
|
||||
.setEquivalence(Enumerations.ConceptMapEquivalence.EQUAL),
|
||||
CM_COPYRIGHT);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,25 @@
|
|||
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.term.IHapiTerminologyLoaderSvc;
|
||||
import ca.uhn.fhir.jpa.term.IRecordHandler;
|
||||
|
|
|
@ -1,20 +1,39 @@
|
|||
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.TermConcept;
|
||||
import ca.uhn.fhir.jpa.term.IRecordHandler;
|
||||
import org.apache.commons.csv.CSVRecord;
|
||||
import org.hl7.fhir.r4.model.ValueSet;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.trim;
|
||||
|
||||
public class LoincPartLinkHandler implements IRecordHandler {
|
||||
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(LoincPartLinkHandler.class);
|
||||
private final Map<String, TermConcept> myCode2Concept;
|
||||
private final TermCodeSystemVersion myCodeSystemVersion;
|
||||
|
||||
|
@ -33,11 +52,11 @@ public class LoincPartLinkHandler implements IRecordHandler {
|
|||
TermConcept loincConcept = myCode2Concept.get(loincNumber);
|
||||
TermConcept partConcept = myCode2Concept.get(partNumber);
|
||||
|
||||
if (loincConcept==null) {
|
||||
if (loincConcept == null) {
|
||||
ourLog.warn("No loinc code: {}", loincNumber);
|
||||
return;
|
||||
}
|
||||
if (partConcept==null) {
|
||||
if (partConcept == null) {
|
||||
ourLog.warn("No part code: {}", partNumber);
|
||||
return;
|
||||
}
|
||||
|
@ -45,5 +64,4 @@ public class LoincPartLinkHandler implements IRecordHandler {
|
|||
// 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;
|
||||
|
||||
/*-
|
||||
* #%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.TermConcept;
|
||||
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 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";
|
||||
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 TermCodeSystemVersion myCodeSystemVersion;
|
||||
private final List<ConceptMap> myConceptMaps;
|
||||
|
@ -76,7 +97,9 @@ public class LoincPartRelatedCodeMappingHandler extends BaseHandler implements I
|
|||
.setTargetDisplay(extCodeDisplayName)
|
||||
.setTargetCodeSystemVersion(extCodeSystemVersion)
|
||||
.setEquivalence(equivalence)
|
||||
.setCopyright(extCodeSystemCopyrightNotice));
|
||||
.setCopyright(extCodeSystemCopyrightNotice),
|
||||
CM_COPYRIGHT
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,25 @@
|
|||
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.TermConcept;
|
||||
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 static final String RSNA_CODES_VS_ID = "RSNA-LOINC-CODES-VS";
|
||||
public static final String RSNA_CODES_VS_URI = "http://loinc.org/rsna-codes";
|
||||
public static final String RSNA_CODES_VS_NAME = "RSNA Playbook";
|
||||
public static final String RSNA_CODES_VS_ID = "loinc-rsna-radiology-playbook";
|
||||
public static final String RSNA_CODES_VS_URI = "http://loinc.org/vs/loinc-rsna-radiology-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_URI = "http://loinc.org/rid-codes";
|
||||
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_URI = "http://loinc.org/rpid-codes";
|
||||
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 TermCodeSystemVersion myCodeSystemVersion;
|
||||
private final Set<String> myPropertyNames;
|
||||
|
@ -118,7 +148,8 @@ public class LoincRsnaPlaybookHandler extends BaseHandler implements IRecordHand
|
|||
.setTargetCodeSystem(RID_CS_URI)
|
||||
.setTargetCode(rid)
|
||||
.setTargetDisplay(preferredName)
|
||||
.setEquivalence(Enumerations.ConceptMapEquivalence.EQUAL));
|
||||
.setEquivalence(Enumerations.ConceptMapEquivalence.EQUAL),
|
||||
CM_COPYRIGHT);
|
||||
}
|
||||
|
||||
// LOINC Term -> Radlex RPID code mappings
|
||||
|
@ -134,7 +165,8 @@ public class LoincRsnaPlaybookHandler extends BaseHandler implements IRecordHand
|
|||
.setTargetCodeSystem(RPID_CS_URI)
|
||||
.setTargetCode(rpid)
|
||||
.setTargetDisplay(longName)
|
||||
.setEquivalence(Enumerations.ConceptMapEquivalence.EQUAL));
|
||||
.setEquivalence(Enumerations.ConceptMapEquivalence.EQUAL),
|
||||
CM_COPYRIGHT);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,25 @@
|
|||
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 org.hl7.fhir.r4.model.ConceptMap;
|
||||
import org.hl7.fhir.r4.model.ValueSet;
|
||||
|
|
|
@ -1,5 +1,25 @@
|
|||
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 org.hl7.fhir.r4.model.ConceptMap;
|
||||
import org.hl7.fhir.r4.model.ValueSet;
|
||||
|
|
|
@ -1,5 +1,25 @@
|
|||
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.term.IHapiTerminologyLoaderSvc;
|
||||
import ca.uhn.fhir.jpa.term.IRecordHandler;
|
||||
|
|
|
@ -1,5 +1,25 @@
|
|||
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 org.apache.commons.csv.CSVRecord;
|
||||
|
||||
|
|
|
@ -1,5 +1,25 @@
|
|||
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.TermConcept;
|
||||
import ca.uhn.fhir.jpa.term.IRecordHandler;
|
||||
|
|
|
@ -1,5 +1,25 @@
|
|||
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.TermConcept;
|
||||
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink;
|
||||
|
|
|
@ -96,7 +96,7 @@ public class TestUtil {
|
|||
assertThat(joinColumn.name(), null);
|
||||
ForeignKey fk = joinColumn.foreignKey();
|
||||
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_"));
|
||||
assertThat(fk.name(), theNames);
|
||||
}
|
||||
|
|
|
@ -252,6 +252,7 @@ public abstract class BaseJpaTest {
|
|||
public Void doInTransaction(TransactionStatus theStatus) {
|
||||
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 " + TermCodeSystem.class.getSimpleName() + " d SET d.myCurrentVersion = null").executeUpdate();
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
@ -279,6 +280,8 @@ public abstract class BaseJpaTest {
|
|||
txTemplate.execute(new TransactionCallback<Void>() {
|
||||
@Override
|
||||
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();
|
||||
for (TermCodeSystem next : entityManager.createQuery("SELECT c FROM " + TermCodeSystem.class.getName() + " c", TermCodeSystem.class).getResultList()) {
|
||||
next.setCurrentVersion(null);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package ca.uhn.fhir.jpa.dao.dstu2;
|
||||
|
||||
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.provider.SystemProviderDstu2Test;
|
||||
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.HTTPVerbEnum;
|
||||
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.UriDt;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
||||
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.interceptor.IServerInterceptor.ActionRequestDetails;
|
||||
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)
|
||||
public void testTransactionFailsWithDuplicateIds() {
|
||||
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
|
||||
public void 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
|
||||
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.server.IBundleProvider;
|
||||
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.interceptor.IServerInterceptor.ActionRequestDetails;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
@ -1439,6 +1440,213 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
|
|||
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
|
||||
public void testTransactionDoubleConditionalCreateOnlyCreatesOne() {
|
||||
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.server.IBundleProvider;
|
||||
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.interceptor.IServerInterceptor.ActionRequestDetails;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
@ -1515,13 +1516,19 @@ public class FhirSystemDaoR4Test extends BaseJpaR4SystemTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testTransactionDoesntDoubleCreate() {
|
||||
public void testTransactionDoesntUpdateUnchangesResourceWithPlaceholderIds() {
|
||||
Bundle output, input;
|
||||
BundleEntryResponseComponent respEntry;
|
||||
IdType createdId;
|
||||
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");
|
||||
|
@ -1542,24 +1549,51 @@ public class FhirSystemDaoR4Test extends BaseJpaR4SystemTest {
|
|||
.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());
|
||||
createdId = new IdType(respEntry.getLocation());
|
||||
assertEquals("Patient", createdId.getResourceType());
|
||||
assertEquals("1", createdId.getVersionIdPart());
|
||||
createdPatientId = new IdType(respEntry.getLocation());
|
||||
assertEquals("Patient", createdPatientId.getResourceType());
|
||||
assertEquals("1", createdPatientId.getVersionIdPart());
|
||||
|
||||
respEntry = output.getEntry().get(1).getResponse();
|
||||
assertEquals("201 Created", respEntry.getStatus());
|
||||
createdId = new IdType(respEntry.getLocation());
|
||||
assertEquals("Observation", createdId.getResourceType());
|
||||
assertEquals("1", createdId.getVersionIdPart());
|
||||
IdType createdObservationId = new IdType(respEntry.getLocation());
|
||||
assertEquals("Observation", createdObservationId.getResourceType());
|
||||
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();
|
||||
|
||||
pat = new Patient();
|
||||
pat.setId(IdType.newRandomUuid());
|
||||
pat.addIdentifier().setSystem("foo").setValue("bar");
|
||||
|
@ -1580,20 +1614,111 @@ public class FhirSystemDaoR4Test extends BaseJpaR4SystemTest {
|
|||
.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());
|
||||
createdId = new IdType(respEntry.getLocation());
|
||||
assertEquals("Patient", createdId.getResourceType());
|
||||
assertEquals("1", createdId.getVersionIdPart());
|
||||
createdObservationId = new IdType(respEntry.getLocation());
|
||||
assertEquals("Patient", createdObservationId.getResourceType());
|
||||
assertEquals("1", createdObservationId.getVersionIdPart());
|
||||
|
||||
respEntry = output.getEntry().get(1).getResponse();
|
||||
assertEquals("200 OK", respEntry.getStatus());
|
||||
createdId = new IdType(respEntry.getLocation());
|
||||
assertEquals("Observation", createdId.getResourceType());
|
||||
assertEquals("1", createdId.getVersionIdPart());
|
||||
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());
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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.dstu3.BaseJpaDstu3Test;
|
||||
import ca.uhn.fhir.jpa.dao.dstu3.SearchParamRegistryDstu3;
|
||||
import ca.uhn.fhir.jpa.provider.TerminologyUploaderProvider;
|
||||
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
||||
import ca.uhn.fhir.jpa.search.ISearchCoordinatorSvc;
|
||||
import ca.uhn.fhir.jpa.subscription.email.SubscriptionEmailInterceptor;
|
||||
|
@ -54,16 +53,16 @@ public abstract class BaseResourceProviderDstu3Test extends BaseJpaDstu3Test {
|
|||
protected static CloseableHttpClient ourHttpClient;
|
||||
protected static int ourPort;
|
||||
protected static RestfulServer ourRestServer;
|
||||
private static Server ourServer;
|
||||
protected static String ourServerBase;
|
||||
protected static GenericWebApplicationContext ourWebApplicationContext;
|
||||
private TerminologyUploaderProvider myTerminologyUploaderProvider;
|
||||
protected static SearchParamRegistryDstu3 ourSearchParamRegistry;
|
||||
protected static DatabaseBackedPagingProvider ourPagingProvider;
|
||||
protected static SubscriptionRestHookInterceptor ourRestHookSubscriptionInterceptor;
|
||||
protected static SubscriptionEmailInterceptor ourEmailSubscriptionInterceptor;
|
||||
protected static ISearchDao mySearchEntityDao;
|
||||
protected static ISearchCoordinatorSvc mySearchCoordinatorSvc;
|
||||
private static Server ourServer;
|
||||
private TerminologyUploaderProviderDstu3 myTerminologyUploaderProvider;
|
||||
|
||||
public BaseResourceProviderDstu3Test() {
|
||||
super();
|
||||
|
@ -93,7 +92,7 @@ public abstract class BaseResourceProviderDstu3Test extends BaseJpaDstu3Test {
|
|||
|
||||
ourRestServer.getFhirContext().setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator());
|
||||
|
||||
myTerminologyUploaderProvider = myAppCtx.getBean(TerminologyUploaderProvider.class);
|
||||
myTerminologyUploaderProvider = myAppCtx.getBean(TerminologyUploaderProviderDstu3.class);
|
||||
|
||||
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 IIdType myExtensionalVsId;
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
|
||||
@Before
|
||||
@Transactional
|
||||
public void before02() throws IOException {
|
||||
|
@ -47,11 +41,11 @@ public class ResourceProviderDstu3CodeSystemTest extends BaseResourceProviderDst
|
|||
ValueSet upload = loadResourceFromClasspath(ValueSet.class, "/extensional-case-3-vs.xml");
|
||||
myExtensionalVsId = myValueSetDao.create(upload, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testLookupOnExternalCode() {
|
||||
ResourceProviderDstu3ValueSetTest.createExternalCs(myCodeSystemDao, myResourceTableDao, myTermSvc, mySrd);
|
||||
|
||||
|
||||
Parameters respParam = ourClient
|
||||
.operation()
|
||||
.onType(CodeSystem.class)
|
||||
|
@ -62,9 +56,9 @@ public class ResourceProviderDstu3CodeSystemTest extends BaseResourceProviderDst
|
|||
|
||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
|
||||
ourLog.info(resp);
|
||||
|
||||
|
||||
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("Parent A", ((StringType)respParam.getParameter().get(1).getValue()).getValue());
|
||||
assertEquals("abstract", respParam.getParameter().get(2).getName());
|
||||
|
@ -82,9 +76,9 @@ public class ResourceProviderDstu3CodeSystemTest extends BaseResourceProviderDst
|
|||
|
||||
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
|
||||
ourLog.info(resp);
|
||||
|
||||
|
||||
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("Parent A", ((StringType)respParam.getParameter().get(1).getValue()).getValue());
|
||||
assertEquals("abstract", respParam.getParameter().get(2).getName());
|
||||
|
@ -104,7 +98,7 @@ public class ResourceProviderDstu3CodeSystemTest extends BaseResourceProviderDst
|
|||
|
||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
|
||||
ourLog.info(resp);
|
||||
|
||||
|
||||
assertEquals("name", respParam.getParameter().get(0).getName());
|
||||
assertEquals(("Unknown"), ((StringType)respParam.getParameter().get(0).getValue()).getValue());
|
||||
assertEquals("display", respParam.getParameter().get(1).getName());
|
||||
|
@ -145,7 +139,7 @@ public class ResourceProviderDstu3CodeSystemTest extends BaseResourceProviderDst
|
|||
|
||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
|
||||
ourLog.info(resp);
|
||||
|
||||
|
||||
assertEquals("name", respParam.getParameter().get(0).getName());
|
||||
assertEquals(("Unknown"), ((StringType)respParam.getParameter().get(0).getValue()).getValue());
|
||||
assertEquals("display", respParam.getParameter().get(1).getName());
|
||||
|
@ -185,7 +179,7 @@ public class ResourceProviderDstu3CodeSystemTest extends BaseResourceProviderDst
|
|||
|
||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
|
||||
ourLog.info(resp);
|
||||
|
||||
|
||||
assertEquals("name", respParam.getParameter().get(0).getName());
|
||||
assertEquals(("Unknown"), ((StringType)respParam.getParameter().get(0).getValue()).getValue());
|
||||
assertEquals("display", respParam.getParameter().get(1).getName());
|
||||
|
@ -247,7 +241,7 @@ public class ResourceProviderDstu3CodeSystemTest extends BaseResourceProviderDst
|
|||
}
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
// @Ignore
|
||||
public void testLookupOperationForBuiltInCode() {
|
||||
|
@ -263,7 +257,7 @@ public class ResourceProviderDstu3CodeSystemTest extends BaseResourceProviderDst
|
|||
|
||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
|
||||
ourLog.info(resp);
|
||||
|
||||
|
||||
assertEquals("name", respParam.getParameter().get(0).getName());
|
||||
assertEquals("Unknown", ((StringType)respParam.getParameter().get(0).getValue()).getValue());
|
||||
assertEquals("display", respParam.getParameter().get(1).getName());
|
||||
|
@ -272,5 +266,10 @@ public class ResourceProviderDstu3CodeSystemTest extends BaseResourceProviderDst
|
|||
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;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.hamcrest.Matchers.greaterThan;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
@ -14,6 +15,7 @@ import java.util.List;
|
|||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.hl7.fhir.dstu3.model.Attachment;
|
||||
import org.hl7.fhir.dstu3.model.IntegerType;
|
||||
|
@ -31,65 +33,81 @@ public class TerminologyUploaderProviderDstu3Test extends BaseResourceProviderDs
|
|||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TerminologyUploaderProviderDstu3Test.class);
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
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;
|
||||
}
|
||||
|
||||
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 testUploadSct() throws Exception {
|
||||
public void testUploadInvalidUrl() 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));
|
||||
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();
|
||||
|
||||
//@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))
|
||||
.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));
|
||||
|
||||
|
||||
/*
|
||||
* 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))
|
||||
.andParameter("package", new Attachment().setUrl("file.zip").setData(packageBytes))
|
||||
.execute();
|
||||
//@formatter:on
|
||||
|
||||
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
|
||||
ourLog.info(resp);
|
||||
|
@ -97,73 +115,42 @@ public class TerminologyUploaderProviderDstu3Test extends BaseResourceProviderDs
|
|||
}
|
||||
|
||||
@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
|
||||
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 + "FOO"))
|
||||
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI))
|
||||
.andParameter("package", new Attachment().setData(packageBytes))
|
||||
.execute();
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("HTTP 400 Bad Request: Unknown URL: http://snomed.info/sctFOO", e.getMessage());
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertThat(e.getMessage(), containsString("Package is missing mandatory url element"));
|
||||
}
|
||||
//@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))
|
||||
.withParameter(Parameters.class, "package", new Attachment().setUrl("foo").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
|
||||
public void testUploadPackageMissingUrl() throws Exception {
|
||||
try {
|
||||
ourClient
|
||||
.operation()
|
||||
|
@ -175,35 +162,55 @@ public class TerminologyUploaderProviderDstu3Test extends BaseResourceProviderDs
|
|||
} 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;
|
||||
@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));
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@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.r4.BaseJpaR4Test;
|
||||
import ca.uhn.fhir.jpa.dao.r4.SearchParamRegistryR4;
|
||||
import ca.uhn.fhir.jpa.provider.TerminologyUploaderProvider;
|
||||
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
||||
import ca.uhn.fhir.jpa.search.ISearchCoordinatorSvc;
|
||||
import ca.uhn.fhir.jpa.subscription.resthook.SubscriptionRestHookInterceptor;
|
||||
|
@ -59,7 +58,7 @@ public abstract class BaseResourceProviderR4Test extends BaseJpaR4Test {
|
|||
protected static ISearchCoordinatorSvc mySearchCoordinatorSvc;
|
||||
private static Server ourServer;
|
||||
protected static GenericWebApplicationContext ourWebApplicationContext;
|
||||
private TerminologyUploaderProvider myTerminologyUploaderProvider;
|
||||
private TerminologyUploaderProviderR4 myTerminologyUploaderProvider;
|
||||
private Object ourGraphQLProvider;
|
||||
private boolean ourRestHookSubscriptionInterceptorRequested;
|
||||
|
||||
|
@ -90,7 +89,7 @@ public abstract class BaseResourceProviderR4Test extends BaseJpaR4Test {
|
|||
|
||||
ourRestServer.getFhirContext().setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator());
|
||||
|
||||
myTerminologyUploaderProvider = myAppCtx.getBean(TerminologyUploaderProvider.class);
|
||||
myTerminologyUploaderProvider = myAppCtx.getBean(TerminologyUploaderProviderR4.class);
|
||||
ourGraphQLProvider = myAppCtx.getBean("myGraphQLProvider");
|
||||
|
||||
ourRestServer.setPlainProviders(mySystemProvider, myTerminologyUploaderProvider, ourGraphQLProvider);
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
package ca.uhn.fhir.jpa.provider.r4;
|
||||
|
||||
import static org.hamcrest.Matchers.greaterThan;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
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.File;
|
||||
|
@ -14,118 +17,45 @@ import java.util.List;
|
|||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
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 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;
|
||||
import static org.hamcrest.Matchers.greaterThan;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class TerminologyUploaderProviderR4Test extends BaseResourceProviderR4Test {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TerminologyUploaderProviderR4Test.class);
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
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;
|
||||
}
|
||||
|
||||
private byte[] createSctZip() throws IOException {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
ZipOutputStream zos = new ZipOutputStream(bos);
|
||||
|
||||
|
||||
@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().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 = myClient
|
||||
.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 = myClient
|
||||
.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 = myClient
|
||||
.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));
|
||||
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
|
||||
public void testUploadInvalidUrl() throws Exception {
|
||||
byte[] packageBytes = createSctZip();
|
||||
|
||||
|
||||
//@formatter:off
|
||||
try {
|
||||
myClient
|
||||
|
@ -133,7 +63,7 @@ public class TerminologyUploaderProviderR4Test extends BaseResourceProviderR4Tes
|
|||
.onServer()
|
||||
.named("upload-external-code-system")
|
||||
.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();
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
|
@ -143,22 +73,41 @@ public class TerminologyUploaderProviderR4Test extends BaseResourceProviderR4Tes
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testUploadMissingUrl() throws Exception {
|
||||
byte[] packageBytes = createSctZip();
|
||||
|
||||
public void testUploadLoinc() throws Exception {
|
||||
byte[] packageBytes = createLoincZip();
|
||||
|
||||
//@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());
|
||||
}
|
||||
Parameters respParam = myClient
|
||||
.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();
|
||||
//@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 = myClient
|
||||
.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();
|
||||
//@formatter:on
|
||||
|
||||
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
|
||||
ourLog.info(resp);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -178,32 +127,74 @@ public class TerminologyUploaderProviderR4Test extends BaseResourceProviderR4Tes
|
|||
//@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)));
|
||||
@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());
|
||||
}
|
||||
zos.close();
|
||||
byte[] packageBytes = bos.toByteArray();
|
||||
return packageBytes;
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@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
|
||||
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 = myClient
|
||||
.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));
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -75,7 +75,7 @@ public class TerminologyLoaderSvcIntegrationDstu3Test extends BaseJpaDstu3Test {
|
|||
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(parameters));
|
||||
|
||||
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.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.hl7.fhir.r4.model.CodeSystem;
|
||||
|
@ -126,8 +127,8 @@ public class TerminologyLoaderSvcSnomedCtTest {
|
|||
try {
|
||||
mySvc.loadSnomedCt(list(bos.toByteArray()), details);
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("Invalid input zip file, expected zip to contain the following name fragments: [Terminology/sct2_Description_Full-en, Terminology/sct2_Relationship_Full, Terminology/sct2_Concept_Full_] but found: []", e.getMessage());
|
||||
} catch (UnprocessableEntityException e) {
|
||||
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 org.hl7.fhir.dstu3.model.CodeSystem;
|
||||
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.r4.model.ValueSet;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
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_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
|
||||
private ITermCodeSystemDao myTermCodeSystemDao;
|
||||
|
||||
|
@ -181,16 +51,16 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
|
|||
TermConcept childAAA = new TermConcept(cs, "childAAA");
|
||||
childAAA.addPropertyString("propA", "valueAAA");
|
||||
childAAA.addPropertyString("propB", "foo");
|
||||
childAAA.addDesignation()
|
||||
.setUseSystem("http://designationsystem")
|
||||
.setUseCode("somedesig")
|
||||
.setUseDisplay("Designation Use")
|
||||
.setValue("Bananas");
|
||||
childAA.addChild(childAAA, RelationshipTypeEnum.ISA);
|
||||
|
||||
TermConcept childAAB = new TermConcept(cs, "childAAB");
|
||||
childAAB.addPropertyString("propA", "valueAAB");
|
||||
childAAB.addPropertyString("propB", "foo");
|
||||
childAAB.addDesignation()
|
||||
.setUseSystem("D1S")
|
||||
.setUseCode("D1C")
|
||||
.setUseDisplay("D1D")
|
||||
.setValue("D1V");
|
||||
childAA.addChild(childAAB, RelationshipTypeEnum.ISA);
|
||||
|
||||
TermConcept childAB = new TermConcept(cs, "childAB");
|
||||
|
@ -199,7 +69,7 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
|
|||
TermConcept parentB = new TermConcept(cs, "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;
|
||||
}
|
||||
|
@ -218,30 +88,48 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
|
|||
TermConcept parentA = new TermConcept(cs, "CS2");
|
||||
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;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindCodesAbove() {
|
||||
IIdType id = createCodeSystem();
|
||||
public void testCreateDuplicateCodeSystemUri() {
|
||||
CodeSystem codeSystem = new CodeSystem();
|
||||
codeSystem.setUrl(CS_URL);
|
||||
codeSystem.setContent(CodeSystemContentMode.NOTPRESENT);
|
||||
IIdType id = myCodeSystemDao.create(codeSystem, mySrd).getId().toUnqualified();
|
||||
|
||||
Set<TermConcept> concepts;
|
||||
Set<String> codes;
|
||||
ResourceTable table = myResourceTableDao.findOne(id.getIdPartAsLong());
|
||||
|
||||
concepts = myTermSvc.findCodesAbove(id.getIdPartAsLong(), id.getVersionIdPartAsLong(), "childAA");
|
||||
codes = toCodes(concepts);
|
||||
assertThat(codes, containsInAnyOrder("ParentA", "childAA"));
|
||||
TermCodeSystemVersion cs = new TermCodeSystemVersion();
|
||||
cs.setResource(table);
|
||||
|
||||
myTermSvc.storeNewCodeSystemVersion(table.getId(), CS_URL, "SYSTEM NAME", cs);
|
||||
|
||||
// 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/"));
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -310,18 +198,143 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
|
|||
assertThat(codes, containsInAnyOrder("ParentA", "childAAA", "childAAB", "childAA", "childAB", "ParentB"));
|
||||
}
|
||||
|
||||
private List<String> toCodesContains(List<ValueSet.ValueSetExpansionContainsComponent> theContains) {
|
||||
List<String> retVal = new ArrayList<>();
|
||||
@Test
|
||||
public void testPropertiesAndDesignationsPreservedInExpansion() {
|
||||
createCodeSystem();
|
||||
|
||||
for (ValueSet.ValueSetExpansionContainsComponent next : theContains) {
|
||||
retVal.add(next.getCode());
|
||||
}
|
||||
List<String> codes;
|
||||
|
||||
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
|
||||
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.setUrl(CS_URL);
|
||||
codeSystem.setContent(CodeSystemContentMode.NOTPRESENT);
|
||||
|
@ -332,31 +345,39 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
|
|||
TermCodeSystemVersion cs = new TermCodeSystemVersion();
|
||||
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
|
||||
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);
|
||||
TermConcept child = new TermConcept();
|
||||
child.setCodeSystemVersion(cs);
|
||||
child.setCode("child");
|
||||
parent.addChild(child, RelationshipTypeEnum.ISA);
|
||||
|
||||
child.addChild(parent, RelationshipTypeEnum.ISA);
|
||||
|
||||
// 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);
|
||||
myTermSvc.storeNewCodeSystemVersion(table.getId(), "http://foo", "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/"));
|
||||
} catch (InvalidRequestException e) {
|
||||
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.dstu3.JpaConformanceProviderDstu3;
|
||||
import ca.uhn.fhir.jpa.provider.dstu3.JpaSystemProviderDstu3;
|
||||
import ca.uhn.fhir.jpa.provider.dstu3.TerminologyUploaderProviderDstu3;
|
||||
import ca.uhn.fhir.jpa.provider.r4.JpaConformanceProviderR4;
|
||||
import ca.uhn.fhir.jpa.provider.r4.JpaSystemProviderR4;
|
||||
import ca.uhn.fhir.jpa.provider.TerminologyUploaderProvider;
|
||||
import ca.uhn.fhir.jpa.provider.r4.TerminologyUploaderProviderR4;
|
||||
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
||||
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
|
@ -50,6 +51,13 @@ public class TestRestfulServer extends RestfulServer {
|
|||
|
||||
private AnnotationConfigWebApplicationContext myAppCtx;
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
super.destroy();
|
||||
ourLog.info("Server is shutting down");
|
||||
myAppCtx.destroy();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
protected void initialize() throws ServletException {
|
||||
|
@ -74,79 +82,79 @@ public class TestRestfulServer extends RestfulServer {
|
|||
ETagSupportEnum etagSupport;
|
||||
String baseUrlProperty;
|
||||
List<Object> plainProviders = new ArrayList<Object>();
|
||||
|
||||
|
||||
switch (fhirVersionParam.trim().toUpperCase()) {
|
||||
case "TDL2":
|
||||
case "DSTU2": {
|
||||
myAppCtx = new AnnotationConfigWebApplicationContext();
|
||||
myAppCtx.setServletConfig(getServletConfig());
|
||||
myAppCtx.setParent(parentAppCtx);
|
||||
if ("TDL2".equals(fhirVersionParam.trim().toUpperCase())) {
|
||||
myAppCtx.register(TdlDstu2Config.class);
|
||||
baseUrlProperty = FHIR_BASEURL_TDL2;
|
||||
} else {
|
||||
myAppCtx.register(TestDstu2Config.class, WebsocketDispatcherConfig.class);
|
||||
baseUrlProperty = FHIR_BASEURL_DSTU2;
|
||||
case "TDL2":
|
||||
case "DSTU2": {
|
||||
myAppCtx = new AnnotationConfigWebApplicationContext();
|
||||
myAppCtx.setServletConfig(getServletConfig());
|
||||
myAppCtx.setParent(parentAppCtx);
|
||||
if ("TDL2".equals(fhirVersionParam.trim().toUpperCase())) {
|
||||
myAppCtx.register(TdlDstu2Config.class);
|
||||
baseUrlProperty = FHIR_BASEURL_TDL2;
|
||||
} else {
|
||||
myAppCtx.register(TestDstu2Config.class, WebsocketDispatcherConfig.class);
|
||||
baseUrlProperty = FHIR_BASEURL_DSTU2;
|
||||
}
|
||||
myAppCtx.refresh();
|
||||
setFhirContext(FhirContext.forDstu2());
|
||||
beans = myAppCtx.getBean("myResourceProvidersDstu2", List.class);
|
||||
plainProviders.add(myAppCtx.getBean("mySystemProviderDstu2", JpaSystemProviderDstu2.class));
|
||||
systemDao = myAppCtx.getBean("mySystemDaoDstu2", IFhirSystemDao.class);
|
||||
etagSupport = ETagSupportEnum.ENABLED;
|
||||
JpaConformanceProviderDstu2 confProvider = new JpaConformanceProviderDstu2(this, systemDao, myAppCtx.getBean(DaoConfig.class));
|
||||
confProvider.setImplementationDescription(implDesc);
|
||||
setServerConformanceProvider(confProvider);
|
||||
break;
|
||||
}
|
||||
myAppCtx.refresh();
|
||||
setFhirContext(FhirContext.forDstu2());
|
||||
beans = myAppCtx.getBean("myResourceProvidersDstu2", List.class);
|
||||
plainProviders.add(myAppCtx.getBean("mySystemProviderDstu2", JpaSystemProviderDstu2.class));
|
||||
systemDao = myAppCtx.getBean("mySystemDaoDstu2", IFhirSystemDao.class);
|
||||
etagSupport = ETagSupportEnum.ENABLED;
|
||||
JpaConformanceProviderDstu2 confProvider = new JpaConformanceProviderDstu2(this, systemDao, myAppCtx.getBean(DaoConfig.class));
|
||||
confProvider.setImplementationDescription(implDesc);
|
||||
setServerConformanceProvider(confProvider);
|
||||
break;
|
||||
}
|
||||
case "TDL3":
|
||||
case "DSTU3": {
|
||||
myAppCtx = new AnnotationConfigWebApplicationContext();
|
||||
myAppCtx.setServletConfig(getServletConfig());
|
||||
myAppCtx.setParent(parentAppCtx);
|
||||
if ("TDL3".equals(fhirVersionParam.trim().toUpperCase())) {
|
||||
myAppCtx.register(TdlDstu3Config.class);
|
||||
baseUrlProperty = FHIR_BASEURL_TDL3;
|
||||
} else {
|
||||
myAppCtx.register(TestDstu3Config.class, WebsocketDispatcherConfig.class);
|
||||
baseUrlProperty = FHIR_BASEURL_DSTU3;
|
||||
case "TDL3":
|
||||
case "DSTU3": {
|
||||
myAppCtx = new AnnotationConfigWebApplicationContext();
|
||||
myAppCtx.setServletConfig(getServletConfig());
|
||||
myAppCtx.setParent(parentAppCtx);
|
||||
if ("TDL3".equals(fhirVersionParam.trim().toUpperCase())) {
|
||||
myAppCtx.register(TdlDstu3Config.class);
|
||||
baseUrlProperty = FHIR_BASEURL_TDL3;
|
||||
} else {
|
||||
myAppCtx.register(TestDstu3Config.class, WebsocketDispatcherConfig.class);
|
||||
baseUrlProperty = FHIR_BASEURL_DSTU3;
|
||||
}
|
||||
myAppCtx.refresh();
|
||||
setFhirContext(FhirContext.forDstu3());
|
||||
beans = myAppCtx.getBean("myResourceProvidersDstu3", List.class);
|
||||
plainProviders.add(myAppCtx.getBean("mySystemProviderDstu3", JpaSystemProviderDstu3.class));
|
||||
systemDao = myAppCtx.getBean("mySystemDaoDstu3", IFhirSystemDao.class);
|
||||
etagSupport = ETagSupportEnum.ENABLED;
|
||||
JpaConformanceProviderDstu3 confProvider = new JpaConformanceProviderDstu3(this, systemDao, myAppCtx.getBean(DaoConfig.class));
|
||||
confProvider.setImplementationDescription(implDesc);
|
||||
setServerConformanceProvider(confProvider);
|
||||
plainProviders.add(myAppCtx.getBean(TerminologyUploaderProviderDstu3.class));
|
||||
break;
|
||||
}
|
||||
myAppCtx.refresh();
|
||||
setFhirContext(FhirContext.forDstu3());
|
||||
beans = myAppCtx.getBean("myResourceProvidersDstu3", List.class);
|
||||
plainProviders.add(myAppCtx.getBean("mySystemProviderDstu3", JpaSystemProviderDstu3.class));
|
||||
systemDao = myAppCtx.getBean("mySystemDaoDstu3", IFhirSystemDao.class);
|
||||
etagSupport = ETagSupportEnum.ENABLED;
|
||||
JpaConformanceProviderDstu3 confProvider = new JpaConformanceProviderDstu3(this, systemDao, myAppCtx.getBean(DaoConfig.class));
|
||||
confProvider.setImplementationDescription(implDesc);
|
||||
setServerConformanceProvider(confProvider);
|
||||
plainProviders.add(myAppCtx.getBean(TerminologyUploaderProvider.class));
|
||||
break;
|
||||
case "R4": {
|
||||
myAppCtx = new AnnotationConfigWebApplicationContext();
|
||||
myAppCtx.setServletConfig(getServletConfig());
|
||||
myAppCtx.setParent(parentAppCtx);
|
||||
myAppCtx.register(TestR4Config.class, WebsocketDispatcherConfig.class);
|
||||
baseUrlProperty = FHIR_BASEURL_R4;
|
||||
myAppCtx.refresh();
|
||||
setFhirContext(FhirContext.forR4());
|
||||
beans = myAppCtx.getBean("myResourceProvidersR4", List.class);
|
||||
plainProviders.add(myAppCtx.getBean("mySystemProviderR4", JpaSystemProviderR4.class));
|
||||
systemDao = myAppCtx.getBean("mySystemDaoR4", IFhirSystemDao.class);
|
||||
etagSupport = ETagSupportEnum.ENABLED;
|
||||
JpaConformanceProviderR4 confProvider = new JpaConformanceProviderR4(this, systemDao, myAppCtx.getBean(DaoConfig.class));
|
||||
confProvider.setImplementationDescription(implDesc);
|
||||
setServerConformanceProvider(confProvider);
|
||||
plainProviders.add(myAppCtx.getBean(TerminologyUploaderProviderR4.class));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new ServletException("Unknown FHIR version specified in init-param[FhirVersion]: " + fhirVersionParam);
|
||||
}
|
||||
case "R4": {
|
||||
myAppCtx = new AnnotationConfigWebApplicationContext();
|
||||
myAppCtx.setServletConfig(getServletConfig());
|
||||
myAppCtx.setParent(parentAppCtx);
|
||||
myAppCtx.register(TestR4Config.class, WebsocketDispatcherConfig.class);
|
||||
baseUrlProperty = FHIR_BASEURL_R4;
|
||||
myAppCtx.refresh();
|
||||
setFhirContext(FhirContext.forR4());
|
||||
beans = myAppCtx.getBean("myResourceProvidersR4", List.class);
|
||||
plainProviders.add(myAppCtx.getBean("mySystemProviderR4", JpaSystemProviderR4.class));
|
||||
systemDao = myAppCtx.getBean("mySystemDaoR4", IFhirSystemDao.class);
|
||||
etagSupport = ETagSupportEnum.ENABLED;
|
||||
JpaConformanceProviderR4 confProvider = new JpaConformanceProviderR4(this, systemDao, myAppCtx.getBean(DaoConfig.class));
|
||||
confProvider.setImplementationDescription(implDesc);
|
||||
setServerConformanceProvider(confProvider);
|
||||
plainProviders.add(myAppCtx.getBean(TerminologyUploaderProvider.class));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new ServletException("Unknown FHIR version specified in init-param[FhirVersion]: " + fhirVersionParam);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* On the DSTU2 endpoint, we want to enable ETag support
|
||||
* On the DSTU2 endpoint, we want to enable ETag support
|
||||
*/
|
||||
setETagSupport(etagSupport);
|
||||
|
||||
|
@ -155,9 +163,9 @@ public class TestRestfulServer extends RestfulServer {
|
|||
*/
|
||||
FhirContext ctx = getFhirContext();
|
||||
ctx.setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator());
|
||||
|
||||
|
||||
/*
|
||||
* The resource and system providers (which actually implement the various FHIR
|
||||
* The resource and system providers (which actually implement the various FHIR
|
||||
* operations in this server) are all retrieved from the spring context above
|
||||
* and are provided to the server here.
|
||||
*/
|
||||
|
@ -187,17 +195,17 @@ public class TestRestfulServer extends RestfulServer {
|
|||
responseHighlighterInterceptor.setShowRequestHeaders(false);
|
||||
responseHighlighterInterceptor.setShowResponseHeaders(true);
|
||||
registerInterceptor(responseHighlighterInterceptor);
|
||||
|
||||
|
||||
registerInterceptor(new BanUnsupportedHttpMethodsInterceptor());
|
||||
|
||||
|
||||
/*
|
||||
* Default to JSON with pretty printing
|
||||
*/
|
||||
setDefaultPrettyPrint(true);
|
||||
setDefaultResponseEncoding(EncodingEnum.JSON);
|
||||
|
||||
|
||||
/*
|
||||
* The server's base URL (e.g. http://fhirtest.uhn.ca/baseDstu2) is
|
||||
* The server's base URL (e.g. http://fhirtest.uhn.ca/baseDstu2) is
|
||||
* pulled from a system property, which is helpful if you want to try
|
||||
* hosting your own copy of this server.
|
||||
*/
|
||||
|
@ -210,12 +218,12 @@ public class TestRestfulServer extends RestfulServer {
|
|||
}
|
||||
}
|
||||
setServerAddressStrategy(new MyHardcodedServerAddressStrategy(baseUrl));
|
||||
|
||||
|
||||
/*
|
||||
* Spool results to the database
|
||||
* Spool results to the database
|
||||
*/
|
||||
setPagingProvider(myAppCtx.getBean(DatabaseBackedPagingProvider.class));
|
||||
|
||||
|
||||
/*
|
||||
* Load interceptors for the server from Spring
|
||||
*/
|
||||
|
@ -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
|
||||
* where this FHIR server is deployed is actually fronted by an Apache HTTPd instance,
|
||||
|
@ -248,7 +249,7 @@ public class TestRestfulServer extends RestfulServer {
|
|||
public String determineServerBase(ServletContext theServletContext, HttpServletRequest theRequest) {
|
||||
/*
|
||||
* This is a bit of a hack, but we want to support both HTTP and HTTPS seamlessly
|
||||
* so we have the outer httpd proxy relay requests to the Java container on
|
||||
* so we have the outer httpd proxy relay requests to the Java container on
|
||||
* port 28080 for http and 28081 for https.
|
||||
*/
|
||||
String retVal = super.determineServerBase(theServletContext, theRequest);
|
||||
|
@ -257,8 +258,8 @@ public class TestRestfulServer extends RestfulServer {
|
|||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package ca.uhn.fhirtest.interceptor;
|
||||
|
||||
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.server.exceptions.ForbiddenOperationException;
|
||||
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 {
|
||||
|
||||
private HashSet<String> myTokens;
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(PublicSecurityInterceptor.class);
|
||||
private HashSet<String> myTokens;
|
||||
|
||||
public PublicSecurityInterceptor() {
|
||||
String passwordsString = System.getProperty("fhir.tdlpass");
|
||||
|
@ -34,7 +34,7 @@ public class PublicSecurityInterceptor extends AuthorizationInterceptor {
|
|||
if (isBlank(authHeader)) {
|
||||
return new RuleBuilder()
|
||||
.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()
|
||||
.build();
|
||||
}
|
||||
|
|
|
@ -279,8 +279,11 @@ public class RestfulServer extends HttpServlet implements IRestfulServer<Servlet
|
|||
supertype = supertype.getSuperclass();
|
||||
}
|
||||
|
||||
count += findResourceMethods(theProvider, clazz);
|
||||
|
||||
try {
|
||||
count += findResourceMethods(theProvider, clazz);
|
||||
} catch (ConfigurationException e) {
|
||||
throw new ConfigurationException("Failure scanning class " + clazz.getSimpleName() + ": " + e.getMessage());
|
||||
}
|
||||
if (count == 0) {
|
||||
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.util.*;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.defaultString;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
public class DefaultProfileValidationSupport implements IValidationSupport {
|
||||
|
@ -33,19 +34,41 @@ public class DefaultProfileValidationSupport implements IValidationSupport {
|
|||
private Map<String, StructureDefinition> myStructureDefinitions;
|
||||
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
|
||||
public ValueSetExpansionComponent expandValueSet(FhirContext theContext, ConceptSetComponent theInclude) {
|
||||
ValueSetExpansionComponent retVal = new ValueSetExpansionComponent();
|
||||
|
||||
Set<String> wantCodes = new HashSet<String>();
|
||||
Set<String> wantCodes = new HashSet<>();
|
||||
for (ConceptReferenceComponent next : theInclude.getConcept()) {
|
||||
wantCodes.add(next.getCode());
|
||||
}
|
||||
|
||||
CodeSystem system = fetchCodeSystem(theContext, theInclude.getSystem());
|
||||
for (ConceptDefinitionComponent next : system.getConcept()) {
|
||||
if (wantCodes.isEmpty() || wantCodes.contains(next.getCode())) {
|
||||
retVal.addContains().setSystem(theInclude.getSystem()).setCode(next.getCode()).setDisplay(next.getDisplay());
|
||||
if (system != null) {
|
||||
List<ConceptDefinitionComponent> concepts = system.getConcept();
|
||||
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.util.*;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.defaultString;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
public class DefaultProfileValidationSupport implements IValidationSupport {
|
||||
|
@ -44,15 +45,37 @@ public class DefaultProfileValidationSupport implements IValidationSupport {
|
|||
}
|
||||
|
||||
CodeSystem system = fetchCodeSystem(theContext, theInclude.getSystem());
|
||||
for (ConceptDefinitionComponent next : system.getConcept()) {
|
||||
if (wantCodes.isEmpty() || wantCodes.contains(next.getCode())) {
|
||||
retVal.addContains().setSystem(theInclude.getSystem()).setCode(next.getCode()).setDisplay(next.getDisplay());
|
||||
if (system != null) {
|
||||
List<ConceptDefinitionComponent> concepts = system.getConcept();
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
public List<IBaseResource> fetchAllConformanceResources(FhirContext theContext) {
|
||||
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.model.CodeSystem;
|
||||
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.ValueSetExpansionComponent;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
@ -14,131 +15,140 @@ import java.util.List;
|
|||
import java.util.Set;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
public class ValidationSupportChain implements IValidationSupport {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ValidationSupportChain.class);
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ValidationSupportChain.class);
|
||||
|
||||
private List<IValidationSupport> myChain;
|
||||
private List<IValidationSupport> myChain;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public ValidationSupportChain() {
|
||||
myChain = new ArrayList<>();
|
||||
}
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public ValidationSupportChain() {
|
||||
myChain = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public ValidationSupportChain(IValidationSupport... theValidationSupportModules) {
|
||||
this();
|
||||
for (IValidationSupport next : theValidationSupportModules) {
|
||||
if (next != null) {
|
||||
myChain.add(next);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public ValidationSupportChain(IValidationSupport... theValidationSupportModules) {
|
||||
this();
|
||||
for (IValidationSupport next : theValidationSupportModules) {
|
||||
if (next != null) {
|
||||
myChain.add(next);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addValidationSupport(IValidationSupport theValidationSupport) {
|
||||
myChain.add(theValidationSupport);
|
||||
}
|
||||
public void addValidationSupport(IValidationSupport theValidationSupport) {
|
||||
myChain.add(theValidationSupport);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSetExpansionComponent expandValueSet(FhirContext theCtx, ConceptSetComponent theInclude) {
|
||||
for (IValidationSupport next : myChain) {
|
||||
if (next.isCodeSystemSupported(theCtx, theInclude.getSystem())) {
|
||||
return next.expandValueSet(theCtx, theInclude);
|
||||
}
|
||||
}
|
||||
return myChain.get(0).expandValueSet(theCtx, theInclude);
|
||||
}
|
||||
@Override
|
||||
public ValueSetExpansionComponent expandValueSet(FhirContext theCtx, ConceptSetComponent theInclude) {
|
||||
for (IValidationSupport next : myChain) {
|
||||
if (isNotBlank(theInclude.getSystem())) {
|
||||
if (next.isCodeSystemSupported(theCtx, theInclude.getSystem())) {
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IBaseResource> fetchAllConformanceResources(FhirContext theContext) {
|
||||
List<IBaseResource> retVal = new ArrayList<>();
|
||||
for (IValidationSupport next : myChain) {
|
||||
List<IBaseResource> candidates = next.fetchAllConformanceResources(theContext);
|
||||
if (candidates != null) {
|
||||
retVal.addAll(candidates);
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
@Override
|
||||
public List<IBaseResource> fetchAllConformanceResources(FhirContext theContext) {
|
||||
List<IBaseResource> retVal = new ArrayList<>();
|
||||
for (IValidationSupport next : myChain) {
|
||||
List<IBaseResource> candidates = next.fetchAllConformanceResources(theContext);
|
||||
if (candidates != null) {
|
||||
retVal.addAll(candidates);
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StructureDefinition> fetchAllStructureDefinitions(FhirContext theContext) {
|
||||
ArrayList<StructureDefinition> retVal = new ArrayList<StructureDefinition>();
|
||||
Set<String> urls = new HashSet<String>();
|
||||
for (IValidationSupport nextSupport : myChain) {
|
||||
for (StructureDefinition next : nextSupport.fetchAllStructureDefinitions(theContext)) {
|
||||
if (isBlank(next.getUrl()) || urls.add(next.getUrl())) {
|
||||
retVal.add(next);
|
||||
}
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
@Override
|
||||
public List<StructureDefinition> fetchAllStructureDefinitions(FhirContext theContext) {
|
||||
ArrayList<StructureDefinition> retVal = new ArrayList<StructureDefinition>();
|
||||
Set<String> urls = new HashSet<String>();
|
||||
for (IValidationSupport nextSupport : myChain) {
|
||||
for (StructureDefinition next : nextSupport.fetchAllStructureDefinitions(theContext)) {
|
||||
if (isBlank(next.getUrl()) || urls.add(next.getUrl())) {
|
||||
retVal.add(next);
|
||||
}
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeSystem fetchCodeSystem(FhirContext theCtx, String theSystem) {
|
||||
for (IValidationSupport next : myChain) {
|
||||
CodeSystem retVal = next.fetchCodeSystem(theCtx, theSystem);
|
||||
if (retVal != null) {
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public CodeSystem fetchCodeSystem(FhirContext theCtx, String theSystem) {
|
||||
for (IValidationSupport next : myChain) {
|
||||
CodeSystem retVal = next.fetchCodeSystem(theCtx, theSystem);
|
||||
if (retVal != null) {
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends IBaseResource> T fetchResource(FhirContext theContext, Class<T> theClass, String theUri) {
|
||||
for (IValidationSupport next : myChain) {
|
||||
T retVal = next.fetchResource(theContext, theClass, theUri);
|
||||
if (retVal != null) {
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public <T extends IBaseResource> T fetchResource(FhirContext theContext, Class<T> theClass, String theUri) {
|
||||
for (IValidationSupport next : myChain) {
|
||||
T retVal = next.fetchResource(theContext, theClass, theUri);
|
||||
if (retVal != null) {
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StructureDefinition fetchStructureDefinition(FhirContext theCtx, String theUrl) {
|
||||
for (IValidationSupport next : myChain) {
|
||||
StructureDefinition retVal = next.fetchStructureDefinition(theCtx, theUrl);
|
||||
if (retVal != null) {
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public StructureDefinition fetchStructureDefinition(FhirContext theCtx, String theUrl) {
|
||||
for (IValidationSupport next : myChain) {
|
||||
StructureDefinition retVal = next.fetchStructureDefinition(theCtx, theUrl);
|
||||
if (retVal != null) {
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCodeSystemSupported(FhirContext theCtx, String theSystem) {
|
||||
for (IValidationSupport next : myChain) {
|
||||
if (next.isCodeSystemSupported(theCtx, theSystem)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean isCodeSystemSupported(FhirContext theCtx, String theSystem) {
|
||||
for (IValidationSupport next : myChain) {
|
||||
if (next.isCodeSystemSupported(theCtx, theSystem)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeValidationResult validateCode(FhirContext theCtx, String theCodeSystem, String theCode, String theDisplay) {
|
||||
@Override
|
||||
public CodeValidationResult validateCode(FhirContext theCtx, String theCodeSystem, String theCode, String theDisplay) {
|
||||
|
||||
ourLog.debug("Validating code {} in chain with {} items", theCode, myChain.size());
|
||||
ourLog.debug("Validating code {} in chain with {} items", theCode, myChain.size());
|
||||
|
||||
for (IValidationSupport next : myChain) {
|
||||
if (next.isCodeSystemSupported(theCtx, theCodeSystem)) {
|
||||
CodeValidationResult result = next.validateCode(theCtx, theCodeSystem, theCode, theDisplay);
|
||||
ourLog.debug("Chain item {} returned outcome {}", next, result.isOk());
|
||||
return result;
|
||||
} else {
|
||||
ourLog.debug("Chain item {} does not support code system {}", next, theCodeSystem);
|
||||
}
|
||||
}
|
||||
return myChain.get(0).validateCode(theCtx, theCodeSystem, theCode, theDisplay);
|
||||
}
|
||||
for (IValidationSupport next : myChain) {
|
||||
if (next.isCodeSystemSupported(theCtx, theCodeSystem)) {
|
||||
CodeValidationResult result = next.validateCode(theCtx, theCodeSystem, theCode, theDisplay);
|
||||
ourLog.debug("Chain item {} returned outcome {}", next, result.isOk());
|
||||
return result;
|
||||
} else {
|
||||
ourLog.debug("Chain item {} does not support code system {}", next, theCodeSystem);
|
||||
}
|
||||
}
|
||||
return myChain.get(0).validateCode(theCtx, theCodeSystem, theCode, theDisplay);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue