Tests all passing
This commit is contained in:
parent
673a3d6272
commit
c5b286921e
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
@ -142,116 +149,6 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle, MetaDt> {
|
|||
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();
|
||||
|
@ -299,10 +196,11 @@ 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());
|
||||
}
|
||||
|
@ -419,6 +317,10 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle, MetaDt> {
|
|||
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;
|
||||
|
@ -435,12 +337,7 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle, MetaDt> {
|
|||
* 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);
|
||||
}
|
||||
}
|
||||
|
@ -609,6 +507,115 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle, MetaDt> {
|
|||
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) {
|
||||
IdDt newId = (IdDt) outcome.getId().toUnqualifiedVersionless();
|
||||
|
@ -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
|
||||
|
|
|
@ -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,14 +29,12 @@ 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;
|
||||
|
||||
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);
|
||||
|
||||
|
|
|
@ -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,9 +362,7 @@ 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: {
|
||||
|
@ -382,7 +375,7 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
|||
matchUrl = performIdSubstitutionsInMatchUrl(theIdSubstitutions, matchUrl);
|
||||
outcome = resourceDao.create(res, matchUrl, false, theRequestDetails);
|
||||
if (nextResourceId != null) {
|
||||
handleTransactionCreateOrUpdateOutcome(theIdSubstitutions, idToPersistedOutcome, nextResourceId, outcome, nextRespEntry, resourceType, res, theRequestDetails);
|
||||
handleTransactionCreateOrUpdateOutcome(theIdSubstitutions, theIdToPersistedOutcome, nextResourceId, outcome, nextRespEntry, resourceType, res, theRequestDetails);
|
||||
}
|
||||
entriesToProcess.put(nextRespEntry, outcome.getEntity());
|
||||
if (outcome.getCreated() == false) {
|
||||
|
@ -460,17 +453,20 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
|||
}
|
||||
}
|
||||
|
||||
handleTransactionCreateOrUpdateOutcome(theIdSubstitutions, idToPersistedOutcome, nextResourceId, outcome, nextRespEntry, resourceType, res, theRequestDetails);
|
||||
if (outcome.getCreated() == Boolean.FALSE) {
|
||||
updatedEntities.add(outcome.getEntity());
|
||||
}
|
||||
|
||||
handleTransactionCreateOrUpdateOutcome(theIdSubstitutions, theIdToPersistedOutcome, nextResourceId, outcome, nextRespEntry, resourceType, res, theRequestDetails);
|
||||
entriesToProcess.put(nextRespEntry, outcome.getEntity());
|
||||
break;
|
||||
}
|
||||
case GET:
|
||||
case NULL:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
theStopWatch.endCurrentTask();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure that there are no conflicts from deletions. E.g. we can't delete something
|
||||
|
@ -479,12 +475,8 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
|||
* end.
|
||||
*/
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
theStopWatch.startTask("Flush Session");
|
||||
if (updatedEntities.contains(nextOutcome.getEntity())) {
|
||||
updateInternal(nextResource, true, false, theRequestDetails, nextOutcome.getEntity(), nextResource.getIdElement(), nextOutcome.getPreviousResource());
|
||||
} else if (!nonUpdatedEntities.contains(nextOutcome.getEntity())) {
|
||||
updateEntity(nextResource, nextOutcome.getEntity(), deletedTimestampOrNull, true, false, theUpdateTime, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
flushJpaSession();
|
||||
|
||||
theStopWatch.endCurrentTask();
|
||||
|
||||
/*
|
||||
* Double check we didn't allow any duplicates we shouldn't have
|
||||
*/
|
||||
|
@ -562,7 +552,7 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
|||
}
|
||||
}
|
||||
|
||||
for (IdType next : allIds) {
|
||||
for (IdType next : theAllIds) {
|
||||
IdType replacement = theIdSubstitutions.get(next);
|
||||
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;
|
||||
|
@ -52,6 +51,7 @@ 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 javolution.io.Struct;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.hl7.fhir.instance.model.api.*;
|
||||
|
@ -323,6 +323,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 +468,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 +543,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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(
|
||||
protected Parameters handleUploadExternalCodeSystem(
|
||||
HttpServletRequest theServletRequest,
|
||||
@OperationParam(name="url", min=1) StringParam theCodeSystemUrl,
|
||||
@OperationParam(name="localfile", min=1, max=OperationParam.MAX_UNLIMITED) List<StringType> theLocalFile,
|
||||
RequestDetails theRequestDetails
|
||||
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,7 +70,7 @@ 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()) {
|
||||
if (!nextFile.exists() || !nextFile.isFile()) {
|
||||
throw new InvalidRequestException("Unknown file: " + nextFile.getName());
|
||||
}
|
||||
localFiles.add(new IHapiTerminologyLoaderSvc.FileDescriptor() {
|
||||
|
@ -92,6 +92,26 @@ public class TerminologyUploaderProvider extends BaseJpaProvider {
|
|||
}
|
||||
}
|
||||
|
||||
if (thePackage != null) {
|
||||
for (Attachment nextPackage : thePackage) {
|
||||
if (isBlank(nextPackage.getUrl())) {
|
||||
throw new UnprocessableEntityException("Package is missing mandatory url element");
|
||||
}
|
||||
|
||||
localFiles.add(new IHapiTerminologyLoaderSvc.FileDescriptor() {
|
||||
@Override
|
||||
public String getFilename() {
|
||||
return nextPackage.getUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getInputStream() {
|
||||
return new ByteArrayInputStream(nextPackage.getData());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
String url = theCodeSystemUrl != null ? theCodeSystemUrl.getValue() : null;
|
||||
url = defaultString(url);
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
package ca.uhn.fhir.jpa.provider.dstu3;
|
||||
|
||||
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,30 @@
|
|||
package ca.uhn.fhir.jpa.provider.r4;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -94,7 +94,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc
|
|||
private boolean myProcessDeferred = true;
|
||||
@Autowired
|
||||
private PlatformTransactionManager myTransactionMgr;
|
||||
@Autowired
|
||||
@Autowired(required = false)
|
||||
private IFhirResourceDaoCodeSystem<?, ?, ?> myCodeSystemResourceDao;
|
||||
|
||||
private void addCodeIfNotAlreadyAdded(String theCodeSystem, ValueSet.ValueSetExpansionComponent theExpansionComponent, Set<String> theAddedCodes, TermConcept theConcept) {
|
||||
|
@ -106,6 +106,19 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc
|
|||
}
|
||||
}
|
||||
|
||||
private void addConceptsToList(ValueSet.ValueSetExpansionComponent theExpansionComponent, Set<String> theAddedCodes, String theSystem, List<CodeSystem.ConceptDefinitionComponent> theConcept) {
|
||||
for (CodeSystem.ConceptDefinitionComponent next : theConcept) {
|
||||
if (!theAddedCodes.contains(next.getCode())) {
|
||||
theAddedCodes.add(next.getCode());
|
||||
ValueSet.ValueSetExpansionContainsComponent contains = theExpansionComponent.addContains();
|
||||
contains.setCode(next.getCode());
|
||||
contains.setSystem(theSystem);
|
||||
contains.setDisplay(next.getDisplay());
|
||||
}
|
||||
addConceptsToList(theExpansionComponent, theAddedCodes, theSystem, next.getConcept());
|
||||
}
|
||||
}
|
||||
|
||||
private void addDisplayFilterExact(QueryBuilder qb, BooleanJunction<?> bool, ValueSet.ConceptSetFilterComponent nextFilter) {
|
||||
bool.must(qb.phrase().onField("myDisplay").sentence(nextFilter.getValue()).createQuery());
|
||||
}
|
||||
|
@ -142,11 +155,28 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc
|
|||
@Override
|
||||
public void deleteCodeSystem(TermCodeSystem theCodeSystem) {
|
||||
ourLog.info(" * Deleting code system {}", theCodeSystem.getPid());
|
||||
|
||||
myEntityManager.flush();
|
||||
TermCodeSystem cs = myCodeSystemDao.findOne(theCodeSystem.getPid());
|
||||
cs.setCurrentVersion(null);
|
||||
myCodeSystemDao.save(cs);
|
||||
myCodeSystemDao.flush();
|
||||
|
||||
for (TermCodeSystemVersion next : myCodeSystemVersionDao.findByCodeSystemResource(theCodeSystem.getPid())) {
|
||||
myConceptParentChildLinkDao.deleteByCodeSystemVersion(next.getPid());
|
||||
myConceptDao.deleteByCodeSystemVersion(next.getPid());
|
||||
for (TermConcept nextConcept : myConceptDao.findByCodeSystemVersion(next.getPid())) {
|
||||
myConceptPropertyDao.delete(nextConcept.getProperties());
|
||||
myConceptDao.delete(nextConcept);
|
||||
}
|
||||
myCodeSystemDao.delete(theCodeSystem.getPid());
|
||||
if (next.getCodeSystem().getCurrentVersion() == next) {
|
||||
next.getCodeSystem().setCurrentVersion(null);
|
||||
myCodeSystemDao.save(next.getCodeSystem());
|
||||
}
|
||||
myCodeSystemVersionDao.delete(next);
|
||||
}
|
||||
myCodeSystemVersionDao.deleteForCodeSystem(theCodeSystem);
|
||||
myCodeSystemDao.delete(theCodeSystem);
|
||||
|
||||
}
|
||||
|
||||
private int ensureParentsSaved(Collection<TermConceptParentChildLink> theParents) {
|
||||
|
@ -171,22 +201,19 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc
|
|||
@Override
|
||||
@Transactional(propagation = Propagation.REQUIRED)
|
||||
public ValueSet expandValueSet(ValueSet theValueSetToExpand) {
|
||||
|
||||
ValueSet.ConceptSetComponent include = theValueSetToExpand.getCompose().getIncludeFirstRep();
|
||||
String system = include.getSystem();
|
||||
ourLog.info("Starting expansion around code system: {}", system);
|
||||
|
||||
TermCodeSystem cs = myCodeSystemDao.findByCodeSystemUri(system);
|
||||
if (cs == null) {
|
||||
throw new InvalidRequestException("Unknown code system: " + system);
|
||||
}
|
||||
|
||||
TermCodeSystemVersion csv = cs.getCurrentVersion();
|
||||
|
||||
ValueSet.ValueSetExpansionComponent expansionComponent = new ValueSet.ValueSetExpansionComponent();
|
||||
Set<String> addedCodes = new HashSet<>();
|
||||
boolean haveIncludeCriteria = false;
|
||||
|
||||
for (ValueSet.ConceptSetComponent include : theValueSetToExpand.getCompose().getInclude()) {
|
||||
String system = include.getSystem();
|
||||
if (isNotBlank(system)) {
|
||||
ourLog.info("Starting expansion around code system: {}", system);
|
||||
|
||||
TermCodeSystem cs = myCodeSystemDao.findByCodeSystemUri(system);
|
||||
if (cs != null) {
|
||||
TermCodeSystemVersion csv = cs.getCurrentVersion();
|
||||
|
||||
/*
|
||||
* Include Concepts
|
||||
*/
|
||||
|
@ -279,14 +306,53 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc
|
|||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// No codesystem matching the URL found in the database
|
||||
|
||||
CodeSystem codeSystemFromContext = getCodeSystemFromContext(system);
|
||||
if (codeSystemFromContext == null) {
|
||||
throw new InvalidRequestException("Unknown code system: " + system);
|
||||
}
|
||||
|
||||
if (include.getConcept().isEmpty() == false) {
|
||||
for (ValueSet.ConceptReferenceComponent next : include.getConcept()) {
|
||||
String nextCode = next.getCode();
|
||||
if (isNotBlank(nextCode) && !addedCodes.contains(nextCode)) {
|
||||
CodeSystem.ConceptDefinitionComponent code = findCode(codeSystemFromContext.getConcept(), nextCode);
|
||||
if (code != null) {
|
||||
addedCodes.add(nextCode);
|
||||
ValueSet.ValueSetExpansionContainsComponent contains = expansionComponent.addContains();
|
||||
contains.setCode(nextCode);
|
||||
contains.setSystem(system);
|
||||
contains.setDisplay(code.getDisplay());
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
List<CodeSystem.ConceptDefinitionComponent> concept = codeSystemFromContext.getConcept();
|
||||
addConceptsToList(expansionComponent, addedCodes, system, concept);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ValueSet valueSet = new ValueSet();
|
||||
valueSet.setExpansion(expansionComponent);
|
||||
return valueSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<VersionIndependentConcept> expandValueSet(String theValueSet) {
|
||||
throw new UnsupportedOperationException(); // FIXME implement
|
||||
protected List<VersionIndependentConcept> expandValueSetAndReturnVersionIndependentConcepts(org.hl7.fhir.r4.model.ValueSet theValueSetToExpandR4) {
|
||||
org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionComponent expandedR4 = expandValueSet(theValueSetToExpandR4).getExpansion();
|
||||
|
||||
ArrayList<VersionIndependentConcept> retVal = new ArrayList<>();
|
||||
for (org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionContainsComponent nextContains : expandedR4.getContains()) {
|
||||
retVal.add(
|
||||
new VersionIndependentConcept()
|
||||
.setSystem(nextContains.getSystem())
|
||||
.setCode(nextContains.getCode()));
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private void fetchChildren(TermConcept theConcept, Set<TermConcept> theSetToPopulate) {
|
||||
|
@ -312,6 +378,16 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc
|
|||
}
|
||||
}
|
||||
|
||||
private CodeSystem.ConceptDefinitionComponent findCode(List<CodeSystem.ConceptDefinitionComponent> theConcepts, String theCode) {
|
||||
for (CodeSystem.ConceptDefinitionComponent next : theConcepts) {
|
||||
if (theCode.equals(next.getCode())) {
|
||||
return next;
|
||||
}
|
||||
findCode(next.getConcept(), theCode);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TermConcept findCode(String theCodeSystem, String theCode) {
|
||||
TermCodeSystemVersion csv = findCurrentCodeSystemVersionForSystem(theCodeSystem);
|
||||
|
@ -398,6 +474,8 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc
|
|||
return myCodeSystemDao.findByCodeSystemUri(theSystem);
|
||||
}
|
||||
|
||||
protected abstract CodeSystem getCodeSystemFromContext(String theSystem);
|
||||
|
||||
private void persistChildren(TermConcept theConcept, TermCodeSystemVersion theCodeSystem, IdentityHashMap<TermConcept, Object> theConceptsStack, int theTotalConcepts) {
|
||||
if (theConceptsStack.put(theConcept, PLACEHOLDER_OBJECT) != null) {
|
||||
return;
|
||||
|
@ -636,12 +714,16 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc
|
|||
for (TermCodeSystemVersion next : existing) {
|
||||
ourLog.info(" * Deleting code system version {}", next.getPid());
|
||||
myConceptParentChildLinkDao.deleteByCodeSystemVersion(next.getPid());
|
||||
myConceptDao.deleteByCodeSystemVersion(next.getPid());
|
||||
for (TermConcept nextConcept : myConceptDao.findByCodeSystemVersion(next.getPid())) {
|
||||
myConceptPropertyDao.delete(nextConcept.getProperties());
|
||||
myConceptDao.delete(nextConcept);
|
||||
}
|
||||
}
|
||||
|
||||
ourLog.info("Flushing...");
|
||||
|
||||
myConceptParentChildLinkDao.flush();
|
||||
myConceptPropertyDao.flush();
|
||||
myConceptDao.flush();
|
||||
|
||||
ourLog.info("Done flushing");
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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,7 @@ 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 " + 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 {
|
||||
|
@ -64,7 +58,7 @@ public class ResourceProviderDstu3CodeSystemTest extends BaseResourceProviderDst
|
|||
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());
|
||||
|
@ -84,7 +78,7 @@ public class ResourceProviderDstu3CodeSystemTest extends BaseResourceProviderDst
|
|||
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());
|
||||
|
@ -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,167 +33,6 @@ 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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testUploadSct() throws Exception {
|
||||
byte[] packageBytes = createSctZip();
|
||||
|
||||
//@formatter:off
|
||||
Parameters respParam = ourClient
|
||||
.operation()
|
||||
.onServer()
|
||||
.named("upload-external-code-system")
|
||||
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI))
|
||||
.andParameter("package", new Attachment().setData(packageBytes))
|
||||
.execute();
|
||||
//@formatter:on
|
||||
|
||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
|
||||
ourLog.info(resp);
|
||||
|
||||
assertThat(((IntegerType)respParam.getParameter().get(0).getValue()).getValue(), greaterThan(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUploadLoinc() throws Exception {
|
||||
byte[] packageBytes = createLoincZip();
|
||||
|
||||
//@formatter:off
|
||||
Parameters respParam = ourClient
|
||||
.operation()
|
||||
.onServer()
|
||||
.named("upload-external-code-system")
|
||||
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.LOINC_URI))
|
||||
.andParameter("package", new Attachment().setData(packageBytes))
|
||||
.execute();
|
||||
//@formatter:on
|
||||
|
||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
|
||||
ourLog.info(resp);
|
||||
|
||||
assertThat(((IntegerType)respParam.getParameter().get(0).getValue()).getValue(), greaterThan(1));
|
||||
|
||||
/*
|
||||
* Try uploading a second time
|
||||
*/
|
||||
|
||||
//@formatter:off
|
||||
respParam = ourClient
|
||||
.operation()
|
||||
.onServer()
|
||||
.named("upload-external-code-system")
|
||||
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.LOINC_URI))
|
||||
.andParameter("package", new Attachment().setData(packageBytes))
|
||||
.execute();
|
||||
//@formatter:on
|
||||
|
||||
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
|
||||
ourLog.info(resp);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUploadSctLocalFile() throws Exception {
|
||||
byte[] packageBytes = createSctZip();
|
||||
File tempFile = File.createTempFile("tmp", ".zip");
|
||||
tempFile.deleteOnExit();
|
||||
|
||||
FileOutputStream fos = new FileOutputStream(tempFile);
|
||||
fos.write(packageBytes);
|
||||
fos.close();
|
||||
|
||||
//@formatter:off
|
||||
Parameters respParam = ourClient
|
||||
.operation()
|
||||
.onServer()
|
||||
.named("upload-external-code-system")
|
||||
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI))
|
||||
.andParameter("localfile", new StringType(tempFile.getAbsolutePath()))
|
||||
.execute();
|
||||
//@formatter:on
|
||||
|
||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
|
||||
ourLog.info(resp);
|
||||
|
||||
assertThat(((IntegerType)respParam.getParameter().get(0).getValue()).getValue(), greaterThan(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUploadInvalidUrl() throws Exception {
|
||||
byte[] packageBytes = createSctZip();
|
||||
|
||||
//@formatter:off
|
||||
try {
|
||||
ourClient
|
||||
.operation()
|
||||
.onServer()
|
||||
.named("upload-external-code-system")
|
||||
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI + "FOO"))
|
||||
.andParameter("package", new Attachment().setData(packageBytes))
|
||||
.execute();
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("HTTP 400 Bad Request: Unknown URL: http://snomed.info/sctFOO", e.getMessage());
|
||||
}
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUploadMissingUrl() throws Exception {
|
||||
byte[] packageBytes = createSctZip();
|
||||
|
||||
//@formatter:off
|
||||
try {
|
||||
ourClient
|
||||
.operation()
|
||||
.onServer()
|
||||
.named("upload-external-code-system")
|
||||
.withParameter(Parameters.class, "package", new Attachment().setData(packageBytes))
|
||||
.execute();
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("HTTP 400 Bad Request: Unknown URL: ", e.getMessage());
|
||||
}
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUploadMissingPackage() throws Exception {
|
||||
//@formatter:off
|
||||
try {
|
||||
ourClient
|
||||
.operation()
|
||||
.onServer()
|
||||
.named("upload-external-code-system")
|
||||
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI))
|
||||
.execute();
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("HTTP 400 Bad Request: No 'localfile' or 'package' parameter, or package had no data", e.getMessage());
|
||||
}
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
private byte[] createSctZip() throws IOException {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
ZipOutputStream zos = new ZipOutputStream(bos);
|
||||
|
||||
List<String> inputNames = Arrays.asList("sct2_Concept_Full_INT_20160131.txt","sct2_Concept_Full-en_INT_20160131.txt","sct2_Description_Full-en_INT_20160131.txt","sct2_Identifier_Full_INT_20160131.txt","sct2_Relationship_Full_INT_20160131.txt","sct2_StatedRelationship_Full_INT_20160131.txt","sct2_TextDefinition_Full-en_INT_20160131.txt");
|
||||
for (String nextName : inputNames) {
|
||||
zos.putNextEntry(new ZipEntry("SnomedCT_Release_INT_20160131_Full/Terminology/" + nextName));
|
||||
zos.write(IOUtils.toByteArray(getClass().getResourceAsStream("/sct/" + nextName)));
|
||||
}
|
||||
zos.close();
|
||||
byte[] packageBytes = bos.toByteArray();
|
||||
return packageBytes;
|
||||
}
|
||||
|
||||
private byte[] createLoincZip() throws IOException {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
ZipOutputStream zos = new ZipOutputStream(bos);
|
||||
|
@ -206,4 +47,170 @@ public class TerminologyUploaderProviderDstu3Test extends BaseResourceProviderDs
|
|||
return packageBytes;
|
||||
}
|
||||
|
||||
private byte[] createSctZip() throws IOException {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
ZipOutputStream zos = new ZipOutputStream(bos);
|
||||
|
||||
List<String> inputNames = Arrays.asList("sct2_Concept_Full_INT_20160131.txt","sct2_Concept_Full-en_INT_20160131.txt","sct2_Description_Full-en_INT_20160131.txt","sct2_Identifier_Full_INT_20160131.txt","sct2_Relationship_Full_INT_20160131.txt","sct2_StatedRelationship_Full_INT_20160131.txt","sct2_TextDefinition_Full-en_INT_20160131.txt");
|
||||
for (String nextName : inputNames) {
|
||||
zos.putNextEntry(new ZipEntry("SnomedCT_Release_INT_20160131_Full/Terminology/" + nextName));
|
||||
byte[] b = IOUtils.toByteArray(getClass().getResourceAsStream("/sct/" + nextName));
|
||||
zos.write(b);
|
||||
}
|
||||
zos.close();
|
||||
byte[] packageBytes = bos.toByteArray();
|
||||
return packageBytes;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUploadInvalidUrl() throws Exception {
|
||||
byte[] packageBytes = createSctZip();
|
||||
|
||||
try {
|
||||
ourClient
|
||||
.operation()
|
||||
.onServer()
|
||||
.named("upload-external-code-system")
|
||||
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI + "FOO"))
|
||||
.andParameter("package", new Attachment().setUrl("foo").setData(packageBytes))
|
||||
.execute();
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("HTTP 400 Bad Request: Unknown URL: http://snomed.info/sctFOO", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUploadLoinc() throws Exception {
|
||||
byte[] packageBytes = createLoincZip();
|
||||
|
||||
Parameters respParam = ourClient
|
||||
.operation()
|
||||
.onServer()
|
||||
.named("upload-external-code-system")
|
||||
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.LOINC_URI))
|
||||
.andParameter("package", new Attachment().setUrl("file.zip").setData(packageBytes))
|
||||
.execute();
|
||||
|
||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
|
||||
ourLog.info(resp);
|
||||
|
||||
assertThat(((IntegerType)respParam.getParameter().get(0).getValue()).getValue(), greaterThan(1));
|
||||
|
||||
/*
|
||||
* Try uploading a second time
|
||||
*/
|
||||
|
||||
respParam = ourClient
|
||||
.operation()
|
||||
.onServer()
|
||||
.named("upload-external-code-system")
|
||||
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.LOINC_URI))
|
||||
.andParameter("package", new Attachment().setUrl("file.zip").setData(packageBytes))
|
||||
.execute();
|
||||
|
||||
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
|
||||
ourLog.info(resp);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUploadMissingPackage() throws Exception {
|
||||
byte[] packageBytes = createLoincZip();
|
||||
try {
|
||||
ourClient
|
||||
.operation()
|
||||
.onServer()
|
||||
.named("upload-external-code-system")
|
||||
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI))
|
||||
.andParameter("package", new Attachment().setData(packageBytes))
|
||||
.execute();
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertThat(e.getMessage(), containsString("Package is missing mandatory url element"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUploadMissingUrl() throws Exception {
|
||||
byte[] packageBytes = createSctZip();
|
||||
|
||||
try {
|
||||
ourClient
|
||||
.operation()
|
||||
.onServer()
|
||||
.named("upload-external-code-system")
|
||||
.withParameter(Parameters.class, "package", new Attachment().setUrl("foo").setData(packageBytes))
|
||||
.execute();
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("HTTP 400 Bad Request: Unknown URL: ", e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUploadPackageMissingUrl() throws Exception {
|
||||
try {
|
||||
ourClient
|
||||
.operation()
|
||||
.onServer()
|
||||
.named("upload-external-code-system")
|
||||
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI))
|
||||
.execute();
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("HTTP 400 Bad Request: No 'localfile' or 'package' parameter, or package had no data", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUploadSct() throws Exception {
|
||||
byte[] packageBytes = createSctZip();
|
||||
|
||||
Parameters respParam = ourClient
|
||||
.operation()
|
||||
.onServer()
|
||||
.named("upload-external-code-system")
|
||||
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI))
|
||||
.andParameter("package", new Attachment().setUrl("file.zip").setData(packageBytes))
|
||||
.execute();
|
||||
|
||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
|
||||
ourLog.info(resp);
|
||||
|
||||
assertThat(((IntegerType)respParam.getParameter().get(0).getValue()).getValue(), greaterThan(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUploadSctLocalFile() throws Exception {
|
||||
byte[] packageBytes = createSctZip();
|
||||
File tempFile = File.createTempFile("tmp", ".zip");
|
||||
tempFile.deleteOnExit();
|
||||
|
||||
FileOutputStream fos = new FileOutputStream(tempFile);
|
||||
fos.write(packageBytes);
|
||||
fos.close();
|
||||
|
||||
ourLog.info("File is: {}", tempFile.getAbsolutePath());
|
||||
|
||||
Parameters respParam = ourClient
|
||||
.operation()
|
||||
.onServer()
|
||||
.named("upload-external-code-system")
|
||||
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI))
|
||||
.andParameter("localfile", new StringType(tempFile.getAbsolutePath()))
|
||||
.execute();
|
||||
|
||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
|
||||
ourLog.info(resp);
|
||||
|
||||
assertThat(((IntegerType)respParam.getParameter().get(0).getValue()).getValue(), greaterThan(1));
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ import ca.uhn.fhir.jpa.config.WebsocketDispatcherConfig;
|
|||
import ca.uhn.fhir.jpa.dao.data.ISearchDao;
|
||||
import ca.uhn.fhir.jpa.dao.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,48 +17,59 @@ 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);
|
||||
|
||||
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 {
|
||||
public void testUploadInvalidUrl() throws Exception {
|
||||
byte[] packageBytes = createSctZip();
|
||||
|
||||
//@formatter:off
|
||||
Parameters respParam = myClient
|
||||
try {
|
||||
myClient
|
||||
.operation()
|
||||
.onServer()
|
||||
.named("upload-external-code-system")
|
||||
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI))
|
||||
.andParameter("package", new Attachment().setData(packageBytes))
|
||||
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI + "FOO"))
|
||||
.andParameter("package", new Attachment().setUrl("file.zip").setData(packageBytes))
|
||||
.execute();
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("HTTP 400 Bad Request: Unknown URL: http://snomed.info/sctFOO", e.getMessage());
|
||||
}
|
||||
//@formatter:on
|
||||
|
||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
|
||||
ourLog.info(resp);
|
||||
|
||||
assertThat(((IntegerType)respParam.getParameter().get(0).getValue()).getValue(), greaterThan(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -68,7 +82,7 @@ public class TerminologyUploaderProviderR4Test extends BaseResourceProviderR4Tes
|
|||
.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
|
||||
|
||||
|
@ -87,7 +101,7 @@ public class TerminologyUploaderProviderR4Test extends BaseResourceProviderR4Tes
|
|||
.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
|
||||
|
||||
|
@ -96,6 +110,62 @@ public class TerminologyUploaderProviderR4Test extends BaseResourceProviderR4Tes
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUploadMissingPackage() throws Exception {
|
||||
//@formatter:off
|
||||
try {
|
||||
myClient
|
||||
.operation()
|
||||
.onServer()
|
||||
.named("upload-external-code-system")
|
||||
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI))
|
||||
.execute();
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("HTTP 400 Bad Request: No 'localfile' or 'package' parameter, or package had no data", e.getMessage());
|
||||
}
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUploadMissingUrl() throws Exception {
|
||||
byte[] packageBytes = createSctZip();
|
||||
|
||||
//@formatter:off
|
||||
try {
|
||||
myClient
|
||||
.operation()
|
||||
.onServer()
|
||||
.named("upload-external-code-system")
|
||||
.withParameter(Parameters.class, "package", new Attachment().setUrl("file.zip").setData(packageBytes))
|
||||
.execute();
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("HTTP 400 Bad Request: Unknown URL: ", e.getMessage());
|
||||
}
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUploadSct() throws Exception {
|
||||
byte[] packageBytes = createSctZip();
|
||||
|
||||
//@formatter:off
|
||||
Parameters respParam = myClient
|
||||
.operation()
|
||||
.onServer()
|
||||
.named("upload-external-code-system")
|
||||
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI))
|
||||
.andParameter("package", new Attachment().setUrl("file.zip").setData(packageBytes))
|
||||
.execute();
|
||||
//@formatter:on
|
||||
|
||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
|
||||
ourLog.info(resp);
|
||||
|
||||
assertThat(((IntegerType) respParam.getParameter().get(0).getValue()).getValue(), greaterThan(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUploadSctLocalFile() throws Exception {
|
||||
byte[] packageBytes = createSctZip();
|
||||
|
@ -122,88 +192,9 @@ public class TerminologyUploaderProviderR4Test extends BaseResourceProviderR4Tes
|
|||
assertThat(((IntegerType) respParam.getParameter().get(0).getValue()).getValue(), greaterThan(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUploadInvalidUrl() throws Exception {
|
||||
byte[] packageBytes = createSctZip();
|
||||
|
||||
//@formatter:off
|
||||
try {
|
||||
myClient
|
||||
.operation()
|
||||
.onServer()
|
||||
.named("upload-external-code-system")
|
||||
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI + "FOO"))
|
||||
.andParameter("package", new Attachment().setData(packageBytes))
|
||||
.execute();
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("HTTP 400 Bad Request: Unknown URL: http://snomed.info/sctFOO", e.getMessage());
|
||||
}
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUploadMissingUrl() throws Exception {
|
||||
byte[] packageBytes = createSctZip();
|
||||
|
||||
//@formatter:off
|
||||
try {
|
||||
myClient
|
||||
.operation()
|
||||
.onServer()
|
||||
.named("upload-external-code-system")
|
||||
.withParameter(Parameters.class, "package", new Attachment().setData(packageBytes))
|
||||
.execute();
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("HTTP 400 Bad Request: Unknown URL: ", e.getMessage());
|
||||
}
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUploadMissingPackage() throws Exception {
|
||||
//@formatter:off
|
||||
try {
|
||||
myClient
|
||||
.operation()
|
||||
.onServer()
|
||||
.named("upload-external-code-system")
|
||||
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URI))
|
||||
.execute();
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("HTTP 400 Bad Request: No 'localfile' or 'package' parameter, or package had no data", e.getMessage());
|
||||
}
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
private byte[] createSctZip() throws IOException {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
ZipOutputStream zos = new ZipOutputStream(bos);
|
||||
|
||||
List<String> inputNames = Arrays.asList("sct2_Concept_Full_INT_20160131.txt","sct2_Concept_Full-en_INT_20160131.txt","sct2_Description_Full-en_INT_20160131.txt","sct2_Identifier_Full_INT_20160131.txt","sct2_Relationship_Full_INT_20160131.txt","sct2_StatedRelationship_Full_INT_20160131.txt","sct2_TextDefinition_Full-en_INT_20160131.txt");
|
||||
for (String nextName : inputNames) {
|
||||
zos.putNextEntry(new ZipEntry("SnomedCT_Release_INT_20160131_Full/Terminology/" + nextName));
|
||||
zos.write(IOUtils.toByteArray(getClass().getResourceAsStream("/sct/" + nextName)));
|
||||
}
|
||||
zos.close();
|
||||
byte[] packageBytes = bos.toByteArray();
|
||||
return packageBytes;
|
||||
}
|
||||
|
||||
private byte[] createLoincZip() throws IOException {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
ZipOutputStream zos = new ZipOutputStream(bos);
|
||||
|
||||
zos.putNextEntry(new ZipEntry("loinc.csv"));
|
||||
zos.write(IOUtils.toByteArray(getClass().getResourceAsStream("/loinc/loinc.csv")));
|
||||
zos.putNextEntry(new ZipEntry("LOINC_2.54_MULTI-AXIAL_HIERARCHY.CSV"));
|
||||
zos.write(IOUtils.toByteArray(getClass().getResourceAsStream("/loinc/LOINC_2.54_MULTI-AXIAL_HIERARCHY.CSV")));
|
||||
zos.close();
|
||||
|
||||
byte[] packageBytes = bos.toByteArray();
|
||||
return packageBytes;
|
||||
@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;
|
||||
|
||||
|
@ -219,24 +89,42 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
|
|||
}
|
||||
|
||||
@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);
|
||||
|
||||
concepts = myTermSvc.findCodesAbove(id.getIdPartAsLong(), id.getVersionIdPartAsLong(), "childAAB");
|
||||
codes = toCodes(concepts);
|
||||
assertThat(codes, containsInAnyOrder("ParentA", "childAA", "childAAB"));
|
||||
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/"));
|
||||
}
|
||||
|
||||
// Try an unknown code
|
||||
concepts = myTermSvc.findCodesAbove(id.getIdPartAsLong(), id.getVersionIdPartAsLong(), "FOO_BAD_CODE");
|
||||
codes = toCodes(concepts);
|
||||
assertThat(codes, empty());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -305,18 +193,118 @@ 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 testFindCodesAbove() {
|
||||
IIdType id = createCodeSystem();
|
||||
|
||||
for (ValueSet.ValueSetExpansionContainsComponent next : theContains) {
|
||||
retVal.add(next.getCode());
|
||||
}
|
||||
Set<TermConcept> concepts;
|
||||
Set<String> codes;
|
||||
|
||||
return retVal;
|
||||
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 testCreateDuplicateCodeSystemUri() {
|
||||
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);
|
||||
|
@ -327,31 +315,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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -279,8 +279,11 @@ public class RestfulServer extends HttpServlet implements IRestfulServer<Servlet
|
|||
supertype = supertype.getSuperclass();
|
||||
}
|
||||
|
||||
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,6 +15,7 @@ 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 {
|
||||
|
||||
|
@ -47,10 +49,18 @@ public class ValidationSupportChain implements IValidationSupport {
|
|||
@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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue