Allow client assigned IDs to be purely numeric in JPA server if
configured to do so
This commit is contained in:
parent
60e81cfb67
commit
821da83d43
|
@ -82,6 +82,7 @@ ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.failedToCreateWithInvalidId=Can not
|
||||||
ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.incorrectResourceType=Incorrect resource type detected for endpoint, found {0} but expected {1}
|
ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.incorrectResourceType=Incorrect resource type detected for endpoint, found {0} but expected {1}
|
||||||
ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.failedToCreateWithClientAssignedNumericId=Can not create resource with ID[{0}], no resource with this ID exists and clients may only assign IDs which contain at least one non-numeric character
|
ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.failedToCreateWithClientAssignedNumericId=Can not create resource with ID[{0}], no resource with this ID exists and clients may only assign IDs which contain at least one non-numeric character
|
||||||
ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.failedToCreateWithClientAssignedId=Can not create resource with ID[{0}], ID must not be supplied on a create (POST) operation
|
ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.failedToCreateWithClientAssignedId=Can not create resource with ID[{0}], ID must not be supplied on a create (POST) operation
|
||||||
|
ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.failedToCreateWithClientAssignedIdNotAllowed=No resource exists on this server resource with ID[{0}], and client-assigned IDs are not enabled.
|
||||||
ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.invalidParameterChain=Invalid parameter chain: {0}
|
ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.invalidParameterChain=Invalid parameter chain: {0}
|
||||||
ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.invalidVersion=Version "{0}" is not valid for resource {1}
|
ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.invalidVersion=Version "{0}" is not valid for resource {1}
|
||||||
ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.multipleParamsWithSameNameOneIsMissingTrue=This server does not know how to handle multiple "{0}" parameters where one has a value of :missing=true
|
ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.multipleParamsWithSameNameOneIsMissingTrue=This server does not know how to handle multiple "{0}" parameters where one has a value of :missing=true
|
||||||
|
|
|
@ -34,10 +34,7 @@ import ca.uhn.fhir.jpa.sp.SearchParamPresenceSvcImpl;
|
||||||
import ca.uhn.fhir.jpa.subscription.email.SubscriptionEmailInterceptor;
|
import ca.uhn.fhir.jpa.subscription.email.SubscriptionEmailInterceptor;
|
||||||
import ca.uhn.fhir.jpa.subscription.resthook.SubscriptionRestHookInterceptor;
|
import ca.uhn.fhir.jpa.subscription.resthook.SubscriptionRestHookInterceptor;
|
||||||
import ca.uhn.fhir.jpa.subscription.websocket.SubscriptionWebsocketInterceptor;
|
import ca.uhn.fhir.jpa.subscription.websocket.SubscriptionWebsocketInterceptor;
|
||||||
import org.hibernate.cfg.AvailableSettings;
|
|
||||||
import org.hibernate.jpa.HibernatePersistenceProvider;
|
import org.hibernate.jpa.HibernatePersistenceProvider;
|
||||||
import org.hibernate.query.criteria.LiteralHandlingMode;
|
|
||||||
import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowire;
|
import org.springframework.beans.factory.annotation.Autowire;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
|
@ -57,7 +54,6 @@ import org.springframework.scheduling.concurrent.ScheduledExecutorFactoryBean;
|
||||||
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
|
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
|
||||||
|
|
||||||
|
@ -92,44 +88,7 @@ public abstract class BaseConfig implements SchedulingConfigurer {
|
||||||
* factory with HAPI FHIR customizations
|
* factory with HAPI FHIR customizations
|
||||||
*/
|
*/
|
||||||
protected LocalContainerEntityManagerFactoryBean entityManagerFactory() {
|
protected LocalContainerEntityManagerFactoryBean entityManagerFactory() {
|
||||||
LocalContainerEntityManagerFactoryBean retVal = new LocalContainerEntityManagerFactoryBean() {
|
LocalContainerEntityManagerFactoryBean retVal = new HapiFhirLocalContainerEntityManagerFactoryBean();
|
||||||
@Override
|
|
||||||
public Map<String, Object> getJpaPropertyMap() {
|
|
||||||
Map<String, Object> retVal = super.getJpaPropertyMap();
|
|
||||||
|
|
||||||
if (!retVal.containsKey(AvailableSettings.CRITERIA_LITERAL_HANDLING_MODE)) {
|
|
||||||
retVal.put(AvailableSettings.CRITERIA_LITERAL_HANDLING_MODE, LiteralHandlingMode.BIND);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!retVal.containsKey(AvailableSettings.CONNECTION_HANDLING)) {
|
|
||||||
retVal.put(AvailableSettings.CONNECTION_HANDLING, PhysicalConnectionHandlingMode.DELAYED_ACQUISITION_AND_HOLD);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Set some performance options
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (!retVal.containsKey(AvailableSettings.STATEMENT_BATCH_SIZE)) {
|
|
||||||
retVal.put(AvailableSettings.STATEMENT_BATCH_SIZE, "30");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!retVal.containsKey(AvailableSettings.ORDER_INSERTS)) {
|
|
||||||
retVal.put(AvailableSettings.ORDER_INSERTS, "true");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!retVal.containsKey(AvailableSettings.ORDER_UPDATES)) {
|
|
||||||
retVal.put(AvailableSettings.ORDER_UPDATES, "true");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!retVal.containsKey(AvailableSettings.BATCH_VERSIONED_DATA)) {
|
|
||||||
retVal.put(AvailableSettings.BATCH_VERSIONED_DATA, "true");
|
|
||||||
}
|
|
||||||
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
};
|
|
||||||
configureEntityManagerFactory(retVal, fhirContext());
|
configureEntityManagerFactory(retVal, fhirContext());
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
package ca.uhn.fhir.jpa.config;
|
||||||
|
|
||||||
|
import org.hibernate.cfg.AvailableSettings;
|
||||||
|
import org.hibernate.query.criteria.LiteralHandlingMode;
|
||||||
|
import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;
|
||||||
|
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is an extension of the Spring/Hibernate LocalContainerEntityManagerFactoryBean
|
||||||
|
* that sets some sensible default property values
|
||||||
|
*/
|
||||||
|
public class HapiFhirLocalContainerEntityManagerFactoryBean extends LocalContainerEntityManagerFactoryBean {
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> getJpaPropertyMap() {
|
||||||
|
Map<String, Object> retVal = super.getJpaPropertyMap();
|
||||||
|
|
||||||
|
if (!retVal.containsKey(AvailableSettings.CRITERIA_LITERAL_HANDLING_MODE)) {
|
||||||
|
retVal.put(AvailableSettings.CRITERIA_LITERAL_HANDLING_MODE, LiteralHandlingMode.BIND);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!retVal.containsKey(AvailableSettings.CONNECTION_HANDLING)) {
|
||||||
|
retVal.put(AvailableSettings.CONNECTION_HANDLING, PhysicalConnectionHandlingMode.DELAYED_ACQUISITION_AND_HOLD);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set some performance options
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!retVal.containsKey(AvailableSettings.STATEMENT_BATCH_SIZE)) {
|
||||||
|
retVal.put(AvailableSettings.STATEMENT_BATCH_SIZE, "30");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!retVal.containsKey(AvailableSettings.ORDER_INSERTS)) {
|
||||||
|
retVal.put(AvailableSettings.ORDER_INSERTS, "true");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!retVal.containsKey(AvailableSettings.ORDER_UPDATES)) {
|
||||||
|
retVal.put(AvailableSettings.ORDER_UPDATES, "true");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!retVal.containsKey(AvailableSettings.BATCH_VERSIONED_DATA)) {
|
||||||
|
retVal.put(AvailableSettings.BATCH_VERSIONED_DATA, "true");
|
||||||
|
}
|
||||||
|
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -21,7 +21,6 @@ import java.util.Set;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
import javax.persistence.EntityManager;
|
import javax.persistence.EntityManager;
|
||||||
|
@ -37,6 +36,7 @@ import javax.persistence.criteria.Root;
|
||||||
import javax.xml.stream.events.Characters;
|
import javax.xml.stream.events.Characters;
|
||||||
import javax.xml.stream.events.XMLEvent;
|
import javax.xml.stream.events.XMLEvent;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.jpa.dao.data.*;
|
||||||
import org.apache.commons.lang3.NotImplementedException;
|
import org.apache.commons.lang3.NotImplementedException;
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
import org.apache.http.NameValuePair;
|
import org.apache.http.NameValuePair;
|
||||||
|
@ -81,21 +81,6 @@ import ca.uhn.fhir.context.FhirVersionEnum;
|
||||||
import ca.uhn.fhir.context.RuntimeChildResourceDefinition;
|
import ca.uhn.fhir.context.RuntimeChildResourceDefinition;
|
||||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||||
import ca.uhn.fhir.jpa.dao.data.IForcedIdDao;
|
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceHistoryTableDao;
|
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceHistoryTagDao;
|
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedCompositeStringUniqueDao;
|
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamCoordsDao;
|
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamDateDao;
|
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamNumberDao;
|
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamQuantityDao;
|
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamStringDao;
|
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamTokenDao;
|
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamUriDao;
|
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceSearchViewDao;
|
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceTableDao;
|
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceTagDao;
|
|
||||||
import ca.uhn.fhir.jpa.dao.data.ISearchDao;
|
|
||||||
import ca.uhn.fhir.jpa.dao.index.IndexingSupport;
|
import ca.uhn.fhir.jpa.dao.index.IndexingSupport;
|
||||||
import ca.uhn.fhir.jpa.dao.index.ResourceIndexedSearchParams;
|
import ca.uhn.fhir.jpa.dao.index.ResourceIndexedSearchParams;
|
||||||
import ca.uhn.fhir.jpa.entity.BaseHasResource;
|
import ca.uhn.fhir.jpa.entity.BaseHasResource;
|
||||||
|
@ -176,7 +161,6 @@ import ca.uhn.fhir.rest.param.UriParam;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException;
|
import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
|
|
||||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
|
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||||
|
@ -261,6 +245,8 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao,
|
||||||
protected EntityManager myEntityManager;
|
protected EntityManager myEntityManager;
|
||||||
@Autowired
|
@Autowired
|
||||||
protected IForcedIdDao myForcedIdDao;
|
protected IForcedIdDao myForcedIdDao;
|
||||||
|
@Autowired
|
||||||
|
protected ISearchResultDao mySearchResultDao;
|
||||||
@Autowired(required = false)
|
@Autowired(required = false)
|
||||||
protected IFulltextSearchSvc myFulltextSearchSvc;
|
protected IFulltextSearchSvc myFulltextSearchSvc;
|
||||||
@Autowired()
|
@Autowired()
|
||||||
|
@ -319,10 +305,14 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void createForcedIdIfNeeded(ResourceTable theEntity, IIdType theId) {
|
/**
|
||||||
if (theId.isEmpty() == false && theId.hasIdPart()) {
|
* Returns the newly created forced ID. If the entity already had a forced ID, or if
|
||||||
if (isValidPid(theId)) {
|
* none was created, returns null.
|
||||||
return;
|
*/
|
||||||
|
protected ForcedId createForcedIdIfNeeded(ResourceTable theEntity, IIdType theId, boolean theCreateForPureNumericIds) {
|
||||||
|
if (theId.isEmpty() == false && theId.hasIdPart() && theEntity.getForcedId() == null) {
|
||||||
|
if (!theCreateForPureNumericIds && isValidPid(theId)) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
ForcedId fid = new ForcedId();
|
ForcedId fid = new ForcedId();
|
||||||
|
@ -330,7 +320,10 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao,
|
||||||
fid.setForcedId(theId.getIdPart());
|
fid.setForcedId(theId.getIdPart());
|
||||||
fid.setResource(theEntity);
|
fid.setResource(theEntity);
|
||||||
theEntity.setForcedId(fid);
|
theEntity.setForcedId(fid);
|
||||||
|
return fid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ExpungeOutcome doExpunge(String theResourceName, Long theResourceId, Long theVersion, ExpungeOptions theExpungeOptions) {
|
protected ExpungeOutcome doExpunge(String theResourceName, Long theResourceId, Long theVersion, ExpungeOptions theExpungeOptions) {
|
||||||
|
@ -373,6 +366,16 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Delete any search result cache entries pointing to the given resource
|
||||||
|
*/
|
||||||
|
if (resourceIds.getContent().size() > 0) {
|
||||||
|
txTemplate.execute(t -> {
|
||||||
|
mySearchResultDao.deleteByResourceIds(resourceIds.getContent());
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Delete historical versions
|
* Delete historical versions
|
||||||
*/
|
*/
|
||||||
|
@ -416,6 +419,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
for (Long next : historicalIds) {
|
for (Long next : historicalIds) {
|
||||||
txTemplate.execute(t -> {
|
txTemplate.execute(t -> {
|
||||||
expungeHistoricalVersion(next);
|
expungeHistoricalVersion(next);
|
||||||
|
@ -675,6 +679,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao,
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public DaoConfig getConfig() {
|
public DaoConfig getConfig() {
|
||||||
return myConfig;
|
return myConfig;
|
||||||
}
|
}
|
||||||
|
@ -705,6 +710,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <R extends IBaseResource> IFhirResourceDao<R> getDao(Class<R> theType) {
|
public <R extends IBaseResource> IFhirResourceDao<R> getDao(Class<R> theType) {
|
||||||
Map<Class<? extends IBaseResource>, IFhirResourceDao<?>> resourceTypeToDao = getDaos();
|
Map<Class<? extends IBaseResource>, IFhirResourceDao<?>> resourceTypeToDao = getDaos();
|
||||||
|
@ -886,6 +892,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao,
|
||||||
theProvider.setSearchCoordinatorSvc(mySearchCoordinatorSvc);
|
theProvider.setSearchCoordinatorSvc(mySearchCoordinatorSvc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean isLogicalReference(IIdType theId) {
|
public boolean isLogicalReference(IIdType theId) {
|
||||||
Set<String> treatReferencesAsLogical = myConfig.getTreatReferencesAsLogical();
|
Set<String> treatReferencesAsLogical = myConfig.getTreatReferencesAsLogical();
|
||||||
if (treatReferencesAsLogical != null) {
|
if (treatReferencesAsLogical != null) {
|
||||||
|
@ -1461,11 +1468,11 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao,
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long translateForcedIdToPid(String theResourceName, String theResourceId) {
|
public Long translateForcedIdToPid(String theResourceName, String theResourceId) {
|
||||||
return translateForcedIdToPids(new IdDt(theResourceName, theResourceId), myForcedIdDao).get(0);
|
return translateForcedIdToPids(getConfig(), new IdDt(theResourceName, theResourceId), myForcedIdDao).get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected List<Long> translateForcedIdToPids(IIdType theId) {
|
protected List<Long> translateForcedIdToPids(IIdType theId) {
|
||||||
return translateForcedIdToPids(theId, myForcedIdDao);
|
return translateForcedIdToPids(getConfig(), theId, myForcedIdDao);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1649,7 +1656,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao,
|
||||||
boolean theForceUpdateVersion, RequestDetails theRequestDetails, ResourceTable theEntity, IIdType
|
boolean theForceUpdateVersion, RequestDetails theRequestDetails, ResourceTable theEntity, IIdType
|
||||||
theResourceId, IBaseResource theOldResource) {
|
theResourceId, IBaseResource theOldResource) {
|
||||||
// Notify interceptors
|
// Notify interceptors
|
||||||
ActionRequestDetails requestDetails = null;
|
ActionRequestDetails requestDetails;
|
||||||
if (theRequestDetails != null) {
|
if (theRequestDetails != null) {
|
||||||
requestDetails = new ActionRequestDetails(theRequestDetails, theResource, theResourceId.getResourceType(), theResourceId);
|
requestDetails = new ActionRequestDetails(theRequestDetails, theResource, theResourceId.getResourceType(), theResourceId);
|
||||||
notifyInterceptors(RestOperationTypeEnum.UPDATE, requestDetails);
|
notifyInterceptors(RestOperationTypeEnum.UPDATE, requestDetails);
|
||||||
|
@ -1988,15 +1995,15 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao,
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static Long translateForcedIdToPid(String theResourceName, String theResourceId, IForcedIdDao
|
protected static Long translateForcedIdToPid(DaoConfig theDaoConfig, String theResourceName, String theResourceId, IForcedIdDao
|
||||||
theForcedIdDao) {
|
theForcedIdDao) {
|
||||||
return translateForcedIdToPids(new IdDt(theResourceName, theResourceId), theForcedIdDao).get(0);
|
return translateForcedIdToPids(theDaoConfig, new IdDt(theResourceName, theResourceId), theForcedIdDao).get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static List<Long> translateForcedIdToPids(IIdType theId, IForcedIdDao theForcedIdDao) {
|
static List<Long> translateForcedIdToPids(DaoConfig theDaoConfig, IIdType theId, IForcedIdDao theForcedIdDao) {
|
||||||
Validate.isTrue(theId.hasIdPart());
|
Validate.isTrue(theId.hasIdPart());
|
||||||
|
|
||||||
if (isValidPid(theId)) {
|
if (theDaoConfig.getResourceClientIdStrategy() != DaoConfig.ClientIdStrategyEnum.ANY && isValidPid(theId)) {
|
||||||
return Collections.singletonList(theId.getIdPartAsLong());
|
return Collections.singletonList(theId.getIdPartAsLong());
|
||||||
} else {
|
} else {
|
||||||
List<ForcedId> forcedId;
|
List<ForcedId> forcedId;
|
||||||
|
|
|
@ -53,16 +53,12 @@ import org.hl7.fhir.instance.model.api.*;
|
||||||
import org.hl7.fhir.r4.model.InstantType;
|
import org.hl7.fhir.r4.model.InstantType;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Required;
|
import org.springframework.beans.factory.annotation.Required;
|
||||||
import org.springframework.lang.NonNull;
|
|
||||||
import org.springframework.transaction.PlatformTransactionManager;
|
import org.springframework.transaction.PlatformTransactionManager;
|
||||||
import org.springframework.transaction.TransactionDefinition;
|
import org.springframework.transaction.TransactionDefinition;
|
||||||
import org.springframework.transaction.TransactionStatus;
|
|
||||||
import org.springframework.transaction.annotation.Propagation;
|
import org.springframework.transaction.annotation.Propagation;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.transaction.support.TransactionCallback;
|
|
||||||
import org.springframework.transaction.support.TransactionTemplate;
|
import org.springframework.transaction.support.TransactionTemplate;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
import javax.persistence.NoResultException;
|
import javax.persistence.NoResultException;
|
||||||
import javax.persistence.TypedQuery;
|
import javax.persistence.TypedQuery;
|
||||||
|
@ -387,12 +383,26 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean serverAssignedId;
|
||||||
if (isNotBlank(theResource.getIdElement().getIdPart())) {
|
if (isNotBlank(theResource.getIdElement().getIdPart())) {
|
||||||
if (isValidPid(theResource.getIdElement())) {
|
switch (myDaoConfig.getResourceClientIdStrategy()) {
|
||||||
throw new UnprocessableEntityException(
|
case NOT_ALLOWED:
|
||||||
"This server cannot create an entity with a user-specified numeric ID - Client should not specify an ID when creating a new resource, or should include at least one letter in the ID to force a client-defined ID");
|
throw new ResourceNotFoundException(
|
||||||
|
getContext().getLocalizer().getMessage(BaseHapiFhirResourceDao.class, "failedToCreateWithClientAssignedIdNotAllowed", theResource.getIdElement().getIdPart()));
|
||||||
|
case ALPHANUMERIC:
|
||||||
|
if (theResource.getIdElement().isIdPartValidLong()) {
|
||||||
|
throw new InvalidRequestException(
|
||||||
|
getContext().getLocalizer().getMessage(BaseHapiFhirResourceDao.class, "failedToCreateWithClientAssignedNumericId", theResource.getIdElement().getIdPart()));
|
||||||
|
}
|
||||||
|
createForcedIdIfNeeded(entity, theResource.getIdElement(), false);
|
||||||
|
break;
|
||||||
|
case ANY:
|
||||||
|
createForcedIdIfNeeded(entity, theResource.getIdElement(), true);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
createForcedIdIfNeeded(entity, theResource.getIdElement());
|
serverAssignedId = false;
|
||||||
|
} else {
|
||||||
|
serverAssignedId = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notify interceptors
|
// Notify interceptors
|
||||||
|
@ -413,8 +423,21 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
|
|
||||||
// Perform actual DB update
|
// Perform actual DB update
|
||||||
ResourceTable updatedEntity = updateEntity(theRequest, theResource, entity, null, thePerformIndexing, thePerformIndexing, theUpdateTime, false, thePerformIndexing);
|
ResourceTable updatedEntity = updateEntity(theRequest, theResource, entity, null, thePerformIndexing, thePerformIndexing, theUpdateTime, false, thePerformIndexing);
|
||||||
theResource.setId(entity.getIdDt());
|
|
||||||
|
|
||||||
|
theResource.setId(entity.getIdDt());
|
||||||
|
if (serverAssignedId) {
|
||||||
|
switch (myDaoConfig.getResourceClientIdStrategy()) {
|
||||||
|
case NOT_ALLOWED:
|
||||||
|
case ALPHANUMERIC:
|
||||||
|
break;
|
||||||
|
case ANY:
|
||||||
|
ForcedId forcedId = createForcedIdIfNeeded(updatedEntity, theResource.getIdElement(), true);
|
||||||
|
if (forcedId != null) {
|
||||||
|
myForcedIdDao.save(forcedId);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we aren't indexing (meaning we're probably executing a sub-operation within a transaction),
|
* If we aren't indexing (meaning we're probably executing a sub-operation within a transaction),
|
||||||
|
@ -1231,10 +1254,6 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
try {
|
try {
|
||||||
entity = readEntityLatestVersion(resourceId);
|
entity = readEntityLatestVersion(resourceId);
|
||||||
} catch (ResourceNotFoundException e) {
|
} catch (ResourceNotFoundException e) {
|
||||||
if (resourceId.isIdPartValidLong()) {
|
|
||||||
throw new InvalidRequestException(
|
|
||||||
getContext().getLocalizer().getMessage(BaseHapiFhirResourceDao.class, "failedToCreateWithClientAssignedNumericId", theResource.getIdElement().getIdPart()));
|
|
||||||
}
|
|
||||||
return doCreate(theResource, null, thePerformIndexing, new Date(), theRequestDetails);
|
return doCreate(theResource, null, thePerformIndexing, new Date(), theRequestDetails);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1325,12 +1344,14 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
|
|
||||||
private void validateGivenIdIsAppropriateToRetrieveResource(IIdType theId, BaseHasResource entity) {
|
private void validateGivenIdIsAppropriateToRetrieveResource(IIdType theId, BaseHasResource entity) {
|
||||||
if (entity.getForcedId() != null) {
|
if (entity.getForcedId() != null) {
|
||||||
if (theId.isIdPartValidLong()) {
|
if (myDaoConfig.getResourceClientIdStrategy() != DaoConfig.ClientIdStrategyEnum.ANY) {
|
||||||
// This means that the resource with the given numeric ID exists, but it has a "forced ID", meaning that
|
if (theId.isIdPartValidLong()) {
|
||||||
// as far as the outside world is concerned, the given ID doesn't exist (it's just an internal pointer
|
// This means that the resource with the given numeric ID exists, but it has a "forced ID", meaning that
|
||||||
// to the
|
// as far as the outside world is concerned, the given ID doesn't exist (it's just an internal pointer
|
||||||
// forced ID)
|
// to the
|
||||||
throw new ResourceNotFoundException(theId);
|
// forced ID)
|
||||||
|
throw new ResourceNotFoundException(theId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -156,6 +156,7 @@ public class DaoConfig {
|
||||||
private List<Integer> mySearchPreFetchThresholds = Arrays.asList(500, 2000, -1);
|
private List<Integer> mySearchPreFetchThresholds = Arrays.asList(500, 2000, -1);
|
||||||
private List<WarmCacheEntry> myWarmCacheEntries = new ArrayList<>();
|
private List<WarmCacheEntry> myWarmCacheEntries = new ArrayList<>();
|
||||||
private boolean myDisableHashBasedSearches;
|
private boolean myDisableHashBasedSearches;
|
||||||
|
private ClientIdStrategyEnum myResourceClientIdStrategy = ClientIdStrategyEnum.ALPHANUMERIC;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
|
@ -642,9 +643,39 @@ public class DaoConfig {
|
||||||
myResourceMetaCountHardLimit = theResourceMetaCountHardLimit;
|
myResourceMetaCountHardLimit = theResourceMetaCountHardLimit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controls the behaviour when a client-assigned ID is encountered, i.e. an HTTP PUT
|
||||||
|
* on a resource ID that does not already exist in the database.
|
||||||
|
* <p>
|
||||||
|
* Default is {@link ClientIdStrategyEnum#ALPHANUMERIC}
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public ClientIdStrategyEnum getResourceClientIdStrategy() {
|
||||||
|
return myResourceClientIdStrategy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controls the behaviour when a client-assigned ID is encountered, i.e. an HTTP PUT
|
||||||
|
* on a resource ID that does not already exist in the database.
|
||||||
|
* <p>
|
||||||
|
* Default is {@link ClientIdStrategyEnum#ALPHANUMERIC}
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param theResourceClientIdStrategy Must not be <code>null</code>
|
||||||
|
*/
|
||||||
|
public void setResourceClientIdStrategy(ClientIdStrategyEnum theResourceClientIdStrategy) {
|
||||||
|
Validate.notNull(theResourceClientIdStrategy, "theClientIdStrategy must not be null");
|
||||||
|
myResourceClientIdStrategy = theResourceClientIdStrategy;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This setting configures the strategy to use in generating IDs for newly
|
* This setting configures the strategy to use in generating IDs for newly
|
||||||
* created resources on the server. The default is {@link IdStrategyEnum#SEQUENTIAL_NUMERIC}.
|
* created resources on the server. The default is {@link IdStrategyEnum#SEQUENTIAL_NUMERIC}.
|
||||||
|
* <p>
|
||||||
|
* This strategy is only used for server-assigned IDs, i.e. for HTTP POST
|
||||||
|
* where the client is requesing that the server store a new resource and give
|
||||||
|
* it an ID.
|
||||||
|
* </p>
|
||||||
*/
|
*/
|
||||||
public IdStrategyEnum getResourceServerIdStrategy() {
|
public IdStrategyEnum getResourceServerIdStrategy() {
|
||||||
return myResourceServerIdStrategy;
|
return myResourceServerIdStrategy;
|
||||||
|
@ -653,8 +684,13 @@ public class DaoConfig {
|
||||||
/**
|
/**
|
||||||
* This setting configures the strategy to use in generating IDs for newly
|
* This setting configures the strategy to use in generating IDs for newly
|
||||||
* created resources on the server. The default is {@link IdStrategyEnum#SEQUENTIAL_NUMERIC}.
|
* created resources on the server. The default is {@link IdStrategyEnum#SEQUENTIAL_NUMERIC}.
|
||||||
|
* <p>
|
||||||
|
* This strategy is only used for server-assigned IDs, i.e. for HTTP POST
|
||||||
|
* where the client is requesing that the server store a new resource and give
|
||||||
|
* it an ID.
|
||||||
|
* </p>
|
||||||
*
|
*
|
||||||
* @param theResourceIdStrategy The strategy. Must not be null.
|
* @param theResourceIdStrategy The strategy. Must not be <code>null</code>.
|
||||||
*/
|
*/
|
||||||
public void setResourceServerIdStrategy(IdStrategyEnum theResourceIdStrategy) {
|
public void setResourceServerIdStrategy(IdStrategyEnum theResourceIdStrategy) {
|
||||||
Validate.notNull(theResourceIdStrategy, "theResourceIdStrategy must not be null");
|
Validate.notNull(theResourceIdStrategy, "theResourceIdStrategy must not be null");
|
||||||
|
@ -1353,18 +1389,8 @@ public class DaoConfig {
|
||||||
* given number.
|
* given number.
|
||||||
* </p>
|
* </p>
|
||||||
*/
|
*/
|
||||||
public void setSearchPreFetchThresholds(List<Integer> thePreFetchThresholds) {
|
public List<Integer> getSearchPreFetchThresholds() {
|
||||||
Validate.isTrue(thePreFetchThresholds.size() > 0, "thePreFetchThresholds must not be empty");
|
return mySearchPreFetchThresholds;
|
||||||
int last = 0;
|
|
||||||
for (Integer nextInteger : thePreFetchThresholds) {
|
|
||||||
int nextInt = nextInteger.intValue();
|
|
||||||
Validate.isTrue(nextInt > 0 || nextInt == -1, nextInt + " is not a valid prefetch threshold");
|
|
||||||
Validate.isTrue(nextInt != last, "Prefetch thresholds must be sequential");
|
|
||||||
Validate.isTrue(nextInt > last || nextInt == -1, "Prefetch thresholds must be sequential");
|
|
||||||
Validate.isTrue(last != -1, "Prefetch thresholds must be sequential");
|
|
||||||
last = nextInt;
|
|
||||||
}
|
|
||||||
mySearchPreFetchThresholds = thePreFetchThresholds;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1380,8 +1406,18 @@ public class DaoConfig {
|
||||||
* given number.
|
* given number.
|
||||||
* </p>
|
* </p>
|
||||||
*/
|
*/
|
||||||
public List<Integer> getSearchPreFetchThresholds() {
|
public void setSearchPreFetchThresholds(List<Integer> thePreFetchThresholds) {
|
||||||
return mySearchPreFetchThresholds;
|
Validate.isTrue(thePreFetchThresholds.size() > 0, "thePreFetchThresholds must not be empty");
|
||||||
|
int last = 0;
|
||||||
|
for (Integer nextInteger : thePreFetchThresholds) {
|
||||||
|
int nextInt = nextInteger.intValue();
|
||||||
|
Validate.isTrue(nextInt > 0 || nextInt == -1, nextInt + " is not a valid prefetch threshold");
|
||||||
|
Validate.isTrue(nextInt != last, "Prefetch thresholds must be sequential");
|
||||||
|
Validate.isTrue(nextInt > last || nextInt == -1, "Prefetch thresholds must be sequential");
|
||||||
|
Validate.isTrue(last != -1, "Prefetch thresholds must be sequential");
|
||||||
|
last = nextInt;
|
||||||
|
}
|
||||||
|
mySearchPreFetchThresholds = thePreFetchThresholds;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1429,6 +1465,36 @@ public class DaoConfig {
|
||||||
UUID
|
UUID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum ClientIdStrategyEnum {
|
||||||
|
/**
|
||||||
|
* Clients are not allowed to supply IDs for resources that do not
|
||||||
|
* already exist
|
||||||
|
*/
|
||||||
|
NOT_ALLOWED,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clients may supply IDs but these IDs are not permitted to be purely
|
||||||
|
* numeric. In other words, values such as "A", "A1" and "000A" would be considered
|
||||||
|
* valid but "123" would not.
|
||||||
|
* <p><b>This is the default setting.</b></p>
|
||||||
|
*/
|
||||||
|
ALPHANUMERIC,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clients may supply any ID including purely numeric IDs. Note that this setting should
|
||||||
|
* only be set on an empty database, or on a database that has always had this setting
|
||||||
|
* set as it causes a "forced ID" to be used for all resources.
|
||||||
|
* <p>
|
||||||
|
* Note that if you use this setting, it is highly recommended that you also
|
||||||
|
* set the {@link #setResourceServerIdStrategy(IdStrategyEnum) ResourceServerIdStrategy}
|
||||||
|
* to {@link IdStrategyEnum#UUID} in order to avoid any potential for conflicts. Otherwise
|
||||||
|
* a database sequence will be used to generate IDs and these IDs can conflict with
|
||||||
|
* client-assigned numeric IDs.
|
||||||
|
* </P>
|
||||||
|
*/
|
||||||
|
ANY
|
||||||
|
}
|
||||||
|
|
||||||
private static void validateTreatBaseUrlsAsLocal(String theUrl) {
|
private static void validateTreatBaseUrlsAsLocal(String theUrl) {
|
||||||
Validate.notBlank(theUrl, "Base URL must not be null or empty");
|
Validate.notBlank(theUrl, "Base URL must not be null or empty");
|
||||||
|
|
||||||
|
|
|
@ -67,6 +67,9 @@ public class FulltextSearchSvcImpl implements IFulltextSearchSvc {
|
||||||
|
|
||||||
private Boolean ourDisabled;
|
private Boolean ourDisabled;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private DaoConfig myDaoConfig;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
|
@ -222,7 +225,7 @@ public class FulltextSearchSvcImpl implements IFulltextSearchSvc {
|
||||||
StringParam idParm = (StringParam) idParam;
|
StringParam idParm = (StringParam) idParam;
|
||||||
idParamValue = idParm.getValue();
|
idParamValue = idParm.getValue();
|
||||||
}
|
}
|
||||||
pid = BaseHapiFhirDao.translateForcedIdToPid(theResourceName, idParamValue, myForcedIdDao);
|
pid = BaseHapiFhirDao.translateForcedIdToPid(myDaoConfig, theResourceName, idParamValue, myForcedIdDao);
|
||||||
}
|
}
|
||||||
|
|
||||||
Long referencingPid = pid;
|
Long referencingPid = pid;
|
||||||
|
@ -275,7 +278,7 @@ public class FulltextSearchSvcImpl implements IFulltextSearchSvc {
|
||||||
if (contextParts.length != 3 || "Patient".equals(contextParts[0]) == false || "$everything".equals(contextParts[2]) == false) {
|
if (contextParts.length != 3 || "Patient".equals(contextParts[0]) == false || "$everything".equals(contextParts[2]) == false) {
|
||||||
throw new InvalidRequestException("Invalid context: " + theContext);
|
throw new InvalidRequestException("Invalid context: " + theContext);
|
||||||
}
|
}
|
||||||
Long pid = BaseHapiFhirDao.translateForcedIdToPid(contextParts[0], contextParts[1], myForcedIdDao);
|
Long pid = BaseHapiFhirDao.translateForcedIdToPid( myDaoConfig, contextParts[0], contextParts[1], myForcedIdDao);
|
||||||
|
|
||||||
FullTextEntityManager em = org.hibernate.search.jpa.Search.getFullTextEntityManager(myEntityManager);
|
FullTextEntityManager em = org.hibernate.search.jpa.Search.getFullTextEntityManager(myEntityManager);
|
||||||
|
|
||||||
|
|
|
@ -1600,7 +1600,7 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
|
|
||||||
if (myParams.get(IAnyResource.SP_RES_ID) != null) {
|
if (myParams.get(IAnyResource.SP_RES_ID) != null) {
|
||||||
StringParam idParm = (StringParam) myParams.get(IAnyResource.SP_RES_ID).get(0).get(0);
|
StringParam idParm = (StringParam) myParams.get(IAnyResource.SP_RES_ID).get(0).get(0);
|
||||||
Long pid = BaseHapiFhirDao.translateForcedIdToPid(myResourceName, idParm.getValue(), myForcedIdDao);
|
Long pid = BaseHapiFhirDao.translateForcedIdToPid(myCallingDao.getConfig(), myResourceName, idParm.getValue(), myForcedIdDao);
|
||||||
if (myAlsoIncludePids == null) {
|
if (myAlsoIncludePids == null) {
|
||||||
myAlsoIncludePids = new ArrayList<>(1);
|
myAlsoIncludePids = new ArrayList<>(1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,11 +46,14 @@ public interface IResourceTableDao extends JpaRepository<ResourceTable, Long> {
|
||||||
@Query("SELECT t.myResourceType as type, COUNT(t.myResourceType) as count FROM ResourceTable t GROUP BY t.myResourceType")
|
@Query("SELECT t.myResourceType as type, COUNT(t.myResourceType) as count FROM ResourceTable t GROUP BY t.myResourceType")
|
||||||
List<Map<?, ?>> getResourceCounts();
|
List<Map<?, ?>> getResourceCounts();
|
||||||
|
|
||||||
|
@Query("SELECT t.myId FROM ResourceTable t WHERE t.myUpdated >= :low AND t.myUpdated <= :high ORDER BY t.myUpdated DESC")
|
||||||
|
Slice<Long> findIdsOfResourcesWithinUpdatedRangeOrderedFromNewest(Pageable thePage, @Param("low") Date theLow, @Param("high") Date theHigh);
|
||||||
|
|
||||||
@Query("SELECT t.myId FROM ResourceTable t WHERE t.myUpdated >= :low AND t.myUpdated <= :high ORDER BY t.myUpdated ASC")
|
@Query("SELECT t.myId FROM ResourceTable t WHERE t.myUpdated >= :low AND t.myUpdated <= :high ORDER BY t.myUpdated ASC")
|
||||||
Slice<Long> findIdsOfResourcesWithinUpdatedRangeOrderedFromOldest(Pageable thePage,@Param("low") Date theLow, @Param("high")Date theHigh);
|
Slice<Long> findIdsOfResourcesWithinUpdatedRangeOrderedFromOldest(Pageable thePage, @Param("low") Date theLow, @Param("high") Date theHigh);
|
||||||
|
|
||||||
@Query("SELECT t.myId FROM ResourceTable t WHERE t.myUpdated >= :low AND t.myUpdated <= :high AND t.myResourceType = :restype ORDER BY t.myUpdated ASC")
|
@Query("SELECT t.myId FROM ResourceTable t WHERE t.myUpdated >= :low AND t.myUpdated <= :high AND t.myResourceType = :restype ORDER BY t.myUpdated ASC")
|
||||||
Slice<Long> findIdsOfResourcesWithinUpdatedRangeOrderedFromOldest(Pageable thePage,@Param("restype") String theResourceType, @Param("low") Date theLow, @Param("high")Date theHigh);
|
Slice<Long> findIdsOfResourcesWithinUpdatedRangeOrderedFromOldest(Pageable thePage, @Param("restype") String theResourceType, @Param("low") Date theLow, @Param("high") Date theHigh);
|
||||||
|
|
||||||
@Modifying
|
@Modifying
|
||||||
@Query("UPDATE ResourceTable t SET t.myIndexStatus = :status WHERE t.myId = :id")
|
@Query("UPDATE ResourceTable t SET t.myIndexStatus = :status WHERE t.myId = :id")
|
||||||
|
|
|
@ -45,6 +45,10 @@ public interface ISearchResultDao extends JpaRepository<SearchResult, Long> {
|
||||||
@Query(value="SELECT r.myId FROM SearchResult r WHERE r.mySearchPid = :search")
|
@Query(value="SELECT r.myId FROM SearchResult r WHERE r.mySearchPid = :search")
|
||||||
Slice<Long> findForSearch(Pageable thePage, @Param("search") Long theSearchPid);
|
Slice<Long> findForSearch(Pageable thePage, @Param("search") Long theSearchPid);
|
||||||
|
|
||||||
|
@Modifying
|
||||||
|
@Query("DELETE FROM SearchResult s WHERE s.myResourcePid IN :ids")
|
||||||
|
void deleteByResourceIds(@Param("ids") List<Long> theContent);
|
||||||
|
|
||||||
@Modifying
|
@Modifying
|
||||||
@Query("DELETE FROM SearchResult s WHERE s.myId IN :ids")
|
@Query("DELETE FROM SearchResult s WHERE s.myId IN :ids")
|
||||||
void deleteByIds(@Param("ids") List<Long> theContent);
|
void deleteByIds(@Param("ids") List<Long> theContent);
|
||||||
|
|
|
@ -44,7 +44,7 @@ public interface IResourceReindexingSvc {
|
||||||
* Does the same thing as {@link #runReindexingPass()} but makes sure to perform at
|
* Does the same thing as {@link #runReindexingPass()} but makes sure to perform at
|
||||||
* least one pass even if one is half finished
|
* least one pass even if one is half finished
|
||||||
*/
|
*/
|
||||||
Integer forceReindexingPass();
|
int forceReindexingPass();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cancels all running and future reindexing jobs. This is mainly intended
|
* Cancels all running and future reindexing jobs. This is mainly intended
|
||||||
|
|
|
@ -196,7 +196,7 @@ public class ResourceReindexingSvcImpl implements IResourceReindexingSvc {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Integer forceReindexingPass() {
|
public int forceReindexingPass() {
|
||||||
myIndexingLock.lock();
|
myIndexingLock.lock();
|
||||||
try {
|
try {
|
||||||
return doReindexingPassInsideLock();
|
return doReindexingPassInsideLock();
|
||||||
|
@ -219,7 +219,7 @@ public class ResourceReindexingSvcImpl implements IResourceReindexingSvc {
|
||||||
expungeJobsMarkedAsDeleted();
|
expungeJobsMarkedAsDeleted();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Integer runReindexJobs() {
|
private int runReindexJobs() {
|
||||||
Collection<ResourceReindexJobEntity> jobs = myTxTemplate.execute(t -> myReindexJobDao.findAll(PageRequest.of(0, 10), false));
|
Collection<ResourceReindexJobEntity> jobs = myTxTemplate.execute(t -> myReindexJobDao.findAll(PageRequest.of(0, 10), false));
|
||||||
assert jobs != null;
|
assert jobs != null;
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ public class FhirResourceDaoR4CodeSystemTest extends BaseJpaR4Test {
|
||||||
myCodeSystemDao.create(cs, mySrd);
|
myCodeSystemDao.create(cs, mySrd);
|
||||||
|
|
||||||
myResourceReindexingSvc.markAllResourcesForReindexing();
|
myResourceReindexingSvc.markAllResourcesForReindexing();
|
||||||
int outcome = myResourceReindexingSvc.runReindexingPass();
|
int outcome = myResourceReindexingSvc.forceReindexingPass();
|
||||||
assertNotEquals(-1, outcome); // -1 means there was a failure
|
assertNotEquals(-1, outcome); // -1 means there was a failure
|
||||||
|
|
||||||
myTermSvc.saveDeferred();
|
myTermSvc.saveDeferred();
|
||||||
|
|
|
@ -3,7 +3,9 @@ package ca.uhn.fhir.jpa.dao.r4;
|
||||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||||
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
|
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
|
||||||
import ca.uhn.fhir.rest.param.StringParam;
|
import ca.uhn.fhir.rest.param.StringParam;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||||
import ca.uhn.fhir.util.TestUtil;
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
|
import org.apache.commons.lang3.time.DateUtils;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
import org.hl7.fhir.r4.model.*;
|
import org.hl7.fhir.r4.model.*;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
|
@ -11,12 +13,14 @@ import org.junit.AfterClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.dao.DataIntegrityViolationException;
|
||||||
|
import org.springframework.data.domain.PageRequest;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.*;
|
import static org.hamcrest.Matchers.*;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.*;
|
||||||
import static org.junit.Assert.assertThat;
|
|
||||||
|
|
||||||
public class FhirResourceDaoR4CreateTest extends BaseJpaR4Test {
|
public class FhirResourceDaoR4CreateTest extends BaseJpaR4Test {
|
||||||
private static final Logger ourLog = LoggerFactory.getLogger(FhirResourceDaoR4CreateTest.class);
|
private static final Logger ourLog = LoggerFactory.getLogger(FhirResourceDaoR4CreateTest.class);
|
||||||
|
@ -24,6 +28,7 @@ public class FhirResourceDaoR4CreateTest extends BaseJpaR4Test {
|
||||||
@After
|
@After
|
||||||
public void afterResetDao() {
|
public void afterResetDao() {
|
||||||
myDaoConfig.setResourceServerIdStrategy(new DaoConfig().getResourceServerIdStrategy());
|
myDaoConfig.setResourceServerIdStrategy(new DaoConfig().getResourceServerIdStrategy());
|
||||||
|
myDaoConfig.setResourceClientIdStrategy(new DaoConfig().getResourceClientIdStrategy());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -69,6 +74,134 @@ public class FhirResourceDaoR4CreateTest extends BaseJpaR4Test {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateWithClientAssignedIdDisallowed() {
|
||||||
|
myDaoConfig.setResourceClientIdStrategy(DaoConfig.ClientIdStrategyEnum.NOT_ALLOWED);
|
||||||
|
|
||||||
|
Patient p = new Patient();
|
||||||
|
p.setId("AAA");
|
||||||
|
p.addName().setFamily("FAM");
|
||||||
|
try {
|
||||||
|
myPatientDao.update(p);
|
||||||
|
fail();
|
||||||
|
} catch (ResourceNotFoundException e) {
|
||||||
|
assertEquals("No resource exists on this server resource with ID[AAA], and client-assigned IDs are not enabled.", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateWithClientAssignedIdPureNumeric() {
|
||||||
|
myDaoConfig.setResourceServerIdStrategy(DaoConfig.IdStrategyEnum.SEQUENTIAL_NUMERIC);
|
||||||
|
myDaoConfig.setResourceClientIdStrategy(DaoConfig.ClientIdStrategyEnum.ANY);
|
||||||
|
|
||||||
|
// Create a server assigned ID
|
||||||
|
Patient p = new Patient();
|
||||||
|
p.setActive(true);
|
||||||
|
IIdType id0 = myPatientDao.create(p).getId();
|
||||||
|
long firstClientAssignedId = id0.getIdPartAsLong();
|
||||||
|
long newId = firstClientAssignedId + 2L;
|
||||||
|
|
||||||
|
// Read it back
|
||||||
|
p = myPatientDao.read(new IdType("Patient/" + firstClientAssignedId));
|
||||||
|
assertEquals(true, p.getActive());
|
||||||
|
|
||||||
|
// Not create a client assigned numeric ID
|
||||||
|
p = new Patient();
|
||||||
|
p.setId("Patient/" + newId);
|
||||||
|
p.addName().setFamily("FAM");
|
||||||
|
IIdType id1 = myPatientDao.update(p).getId();
|
||||||
|
|
||||||
|
assertEquals(Long.toString(newId), id1.getIdPart());
|
||||||
|
assertEquals("1", id1.getVersionIdPart());
|
||||||
|
|
||||||
|
p = myPatientDao.read(id1);
|
||||||
|
assertEquals("FAM", p.getNameFirstRep().getFamily());
|
||||||
|
|
||||||
|
// Update it
|
||||||
|
p = new Patient();
|
||||||
|
p.setId("Patient/" + newId);
|
||||||
|
p.addName().setFamily("FAM2");
|
||||||
|
id1 = myPatientDao.update(p).getId();
|
||||||
|
|
||||||
|
assertEquals(Long.toString(newId), id1.getIdPart());
|
||||||
|
assertEquals("2", id1.getVersionIdPart());
|
||||||
|
|
||||||
|
p = myPatientDao.read(id1);
|
||||||
|
assertEquals("FAM2", p.getNameFirstRep().getFamily());
|
||||||
|
|
||||||
|
// Try to create another server-assigned. This should fail since we have a
|
||||||
|
// a conflict.
|
||||||
|
p = new Patient();
|
||||||
|
p.setActive(false);
|
||||||
|
try {
|
||||||
|
myPatientDao.create(p).getId();
|
||||||
|
fail();
|
||||||
|
} catch (DataIntegrityViolationException e) {
|
||||||
|
// good
|
||||||
|
}
|
||||||
|
|
||||||
|
ourLog.info("ID0: {}", id0);
|
||||||
|
ourLog.info("ID1: {}", id1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateWithClientAssignedIdPureNumericServerIdUuid() {
|
||||||
|
myDaoConfig.setResourceServerIdStrategy(DaoConfig.IdStrategyEnum.UUID);
|
||||||
|
myDaoConfig.setResourceClientIdStrategy(DaoConfig.ClientIdStrategyEnum.ANY);
|
||||||
|
|
||||||
|
// Create a server assigned ID
|
||||||
|
Patient p = new Patient();
|
||||||
|
p.setActive(true);
|
||||||
|
IIdType id0 = myPatientDao.create(p).getId();
|
||||||
|
|
||||||
|
// Read it back
|
||||||
|
p = myPatientDao.read(id0.toUnqualifiedVersionless());
|
||||||
|
assertEquals(true, p.getActive());
|
||||||
|
|
||||||
|
// Pick an ID that was already used as an internal PID
|
||||||
|
Long newId = runInTransaction(() -> myResourceTableDao.findIdsOfResourcesWithinUpdatedRangeOrderedFromNewest(
|
||||||
|
PageRequest.of(0, 1),
|
||||||
|
DateUtils.addDays(new Date(), -1),
|
||||||
|
DateUtils.addDays(new Date(), 1)
|
||||||
|
).getContent().get(0));
|
||||||
|
|
||||||
|
// Not create a client assigned numeric ID
|
||||||
|
p = new Patient();
|
||||||
|
p.setId("Patient/" + newId);
|
||||||
|
p.addName().setFamily("FAM");
|
||||||
|
IIdType id1 = myPatientDao.update(p).getId();
|
||||||
|
|
||||||
|
assertEquals(Long.toString(newId), id1.getIdPart());
|
||||||
|
assertEquals("1", id1.getVersionIdPart());
|
||||||
|
|
||||||
|
// Read it back
|
||||||
|
p = myPatientDao.read(id1);
|
||||||
|
assertEquals("FAM", p.getNameFirstRep().getFamily());
|
||||||
|
|
||||||
|
// Update it
|
||||||
|
p = new Patient();
|
||||||
|
p.setId("Patient/" + newId);
|
||||||
|
p.addName().setFamily("FAM2");
|
||||||
|
id1 = myPatientDao.update(p).getId();
|
||||||
|
|
||||||
|
assertEquals(Long.toString(newId), id1.getIdPart());
|
||||||
|
assertEquals("2", id1.getVersionIdPart());
|
||||||
|
|
||||||
|
p = myPatientDao.read(id1);
|
||||||
|
assertEquals("FAM2", p.getNameFirstRep().getFamily());
|
||||||
|
|
||||||
|
// Try to create another server-assigned. This should fail since we have a
|
||||||
|
// a conflict.
|
||||||
|
p = new Patient();
|
||||||
|
p.setActive(false);
|
||||||
|
IIdType id2 = myPatientDao.create(p).getId();
|
||||||
|
|
||||||
|
ourLog.info("ID0: {}", id0);
|
||||||
|
ourLog.info("ID1: {}", id1);
|
||||||
|
ourLog.info("ID2: {}", id2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTransactionCreateWithUuidResourceStrategy() {
|
public void testTransactionCreateWithUuidResourceStrategy() {
|
||||||
myDaoConfig.setResourceServerIdStrategy(DaoConfig.IdStrategyEnum.UUID);
|
myDaoConfig.setResourceServerIdStrategy(DaoConfig.IdStrategyEnum.UUID);
|
||||||
|
|
|
@ -146,8 +146,8 @@ public class FhirResourceDaoR4SearchCustomSearchParamTest extends BaseJpaR4Test
|
||||||
|
|
||||||
mySearchParameterDao.create(fooSp, mySrd);
|
mySearchParameterDao.create(fooSp, mySrd);
|
||||||
|
|
||||||
assertEquals(1, myResourceReindexingSvc.forceReindexingPass().intValue());
|
assertEquals(1, myResourceReindexingSvc.forceReindexingPass());
|
||||||
assertEquals(0, myResourceReindexingSvc.forceReindexingPass().intValue());
|
assertEquals(0, myResourceReindexingSvc.forceReindexingPass());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -182,7 +182,7 @@ public class FhirResourceDaoR4Test extends BaseJpaR4Test {
|
||||||
});
|
});
|
||||||
|
|
||||||
myResourceReindexingSvc.markAllResourcesForReindexing();
|
myResourceReindexingSvc.markAllResourcesForReindexing();
|
||||||
myResourceReindexingSvc.runReindexingPass();
|
myResourceReindexingSvc.forceReindexingPass();
|
||||||
|
|
||||||
runInTransaction(() -> {
|
runInTransaction(() -> {
|
||||||
Optional<ResourceTable> tableOpt = myResourceTableDao.findById(id1.getIdPartAsLong());
|
Optional<ResourceTable> tableOpt = myResourceTableDao.findById(id1.getIdPartAsLong());
|
||||||
|
@ -225,7 +225,7 @@ public class FhirResourceDaoR4Test extends BaseJpaR4Test {
|
||||||
});
|
});
|
||||||
|
|
||||||
myResourceReindexingSvc.markAllResourcesForReindexing();
|
myResourceReindexingSvc.markAllResourcesForReindexing();
|
||||||
myResourceReindexingSvc.runReindexingPass();
|
myResourceReindexingSvc.forceReindexingPass();
|
||||||
|
|
||||||
runInTransaction(() -> {
|
runInTransaction(() -> {
|
||||||
Optional<ResourceTable> tableOpt = myResourceTableDao.findById(id1.getIdPartAsLong());
|
Optional<ResourceTable> tableOpt = myResourceTableDao.findById(id1.getIdPartAsLong());
|
||||||
|
|
|
@ -2,15 +2,14 @@ package ca.uhn.fhir.jpa.provider.r4;
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
||||||
import ca.uhn.fhir.jpa.dao.data.IForcedIdDao;
|
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceHistoryTableDao;
|
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceTableDao;
|
|
||||||
import ca.uhn.fhir.jpa.util.ExpungeOptions;
|
import ca.uhn.fhir.jpa.util.ExpungeOptions;
|
||||||
|
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
|
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
|
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||||
import ca.uhn.fhir.util.TestUtil;
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
import org.hamcrest.Matchers;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
import org.hl7.fhir.r4.model.IdType;
|
import org.hl7.fhir.r4.model.IdType;
|
||||||
import org.hl7.fhir.r4.model.Observation;
|
import org.hl7.fhir.r4.model.Observation;
|
||||||
|
@ -19,7 +18,8 @@ import org.junit.After;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.empty;
|
import static org.hamcrest.Matchers.empty;
|
||||||
import static org.hamcrest.Matchers.not;
|
import static org.hamcrest.Matchers.not;
|
||||||
|
@ -168,17 +168,17 @@ public class ExpungeR4Test extends BaseResourceProviderR4Test {
|
||||||
myPatientDao.update(p).getId();
|
myPatientDao.update(p).getId();
|
||||||
myPatientDao.delete(new IdType("Patient/TEST"));
|
myPatientDao.delete(new IdType("Patient/TEST"));
|
||||||
|
|
||||||
runInTransaction(()-> assertThat(myResourceTableDao.findAll(), not(empty())));
|
runInTransaction(() -> assertThat(myResourceTableDao.findAll(), not(empty())));
|
||||||
runInTransaction(()-> assertThat(myResourceHistoryTableDao.findAll(), not(empty())));
|
runInTransaction(() -> assertThat(myResourceHistoryTableDao.findAll(), not(empty())));
|
||||||
runInTransaction(()-> assertThat(myForcedIdDao.findAll(), not(empty())));
|
runInTransaction(() -> assertThat(myForcedIdDao.findAll(), not(empty())));
|
||||||
|
|
||||||
myPatientDao.expunge(new ExpungeOptions()
|
myPatientDao.expunge(new ExpungeOptions()
|
||||||
.setExpungeDeletedResources(true)
|
.setExpungeDeletedResources(true)
|
||||||
.setExpungeOldVersions(true));
|
.setExpungeOldVersions(true));
|
||||||
|
|
||||||
runInTransaction(()-> assertThat(myResourceTableDao.findAll(), empty()));
|
runInTransaction(() -> assertThat(myResourceTableDao.findAll(), empty()));
|
||||||
runInTransaction(()-> assertThat(myResourceHistoryTableDao.findAll(), empty()));
|
runInTransaction(() -> assertThat(myResourceHistoryTableDao.findAll(), empty()));
|
||||||
runInTransaction(()-> assertThat(myForcedIdDao.findAll(), empty()));
|
runInTransaction(() -> assertThat(myForcedIdDao.findAll(), empty()));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -332,6 +332,61 @@ public class ExpungeR4Test extends BaseResourceProviderR4Test {
|
||||||
assertGone(myDeletedObservationId);
|
assertGone(myDeletedObservationId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExpungeEverythingWhereResourceInSearchResults() {
|
||||||
|
createStandardPatients();
|
||||||
|
|
||||||
|
IBundleProvider search = myPatientDao.search(new SearchParameterMap());
|
||||||
|
assertEquals(2, search.size().intValue());
|
||||||
|
search.getResources(0, 2);
|
||||||
|
|
||||||
|
runInTransaction(() -> {
|
||||||
|
assertEquals(2, mySearchResultDao.count());
|
||||||
|
});
|
||||||
|
|
||||||
|
mySystemDao.expunge(new ExpungeOptions()
|
||||||
|
.setExpungeEverything(true));
|
||||||
|
|
||||||
|
// Everything deleted
|
||||||
|
assertExpunged(myOneVersionPatientId);
|
||||||
|
assertExpunged(myTwoVersionPatientId.withVersion("1"));
|
||||||
|
assertExpunged(myTwoVersionPatientId.withVersion("2"));
|
||||||
|
assertExpunged(myDeletedPatientId.withVersion("1"));
|
||||||
|
assertExpunged(myDeletedPatientId);
|
||||||
|
|
||||||
|
// Everything deleted
|
||||||
|
assertExpunged(myOneVersionObservationId);
|
||||||
|
assertExpunged(myTwoVersionObservationId.withVersion("1"));
|
||||||
|
assertExpunged(myTwoVersionObservationId.withVersion("2"));
|
||||||
|
assertExpunged(myDeletedObservationId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExpungeDeletedWhereResourceInSearchResults() {
|
||||||
|
createStandardPatients();
|
||||||
|
|
||||||
|
IBundleProvider search = myPatientDao.search(new SearchParameterMap());
|
||||||
|
assertEquals(2, search.size().intValue());
|
||||||
|
List<IBaseResource> resources = search.getResources(0, 2);
|
||||||
|
myPatientDao.delete(resources.get(0).getIdElement());
|
||||||
|
|
||||||
|
runInTransaction(() -> {
|
||||||
|
assertEquals(2, mySearchResultDao.count());
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
mySystemDao.expunge(new ExpungeOptions()
|
||||||
|
.setExpungeDeletedResources(true));
|
||||||
|
|
||||||
|
// Everything deleted
|
||||||
|
assertExpunged(myOneVersionPatientId);
|
||||||
|
assertStillThere(myTwoVersionPatientId.withVersion("1"));
|
||||||
|
assertStillThere(myTwoVersionPatientId.withVersion("2"));
|
||||||
|
assertExpunged(myDeletedPatientId.withVersion("1"));
|
||||||
|
assertExpunged(myDeletedPatientId);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@AfterClass
|
@AfterClass
|
||||||
public static void afterClassClearContext() {
|
public static void afterClassClearContext() {
|
||||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||||
|
|
|
@ -24,6 +24,7 @@ import org.junit.*;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
@ -35,14 +36,14 @@ import static org.junit.Assert.fail;
|
||||||
public class RestHookTestDstu3Test extends BaseResourceProviderDstu3Test {
|
public class RestHookTestDstu3Test extends BaseResourceProviderDstu3Test {
|
||||||
|
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RestHookTestDstu3Test.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RestHookTestDstu3Test.class);
|
||||||
private static List<Observation> ourCreatedObservations = Lists.newArrayList();
|
private static List<Observation> ourCreatedObservations = Collections.synchronizedList(Lists.newArrayList());
|
||||||
private static int ourListenerPort;
|
private static int ourListenerPort;
|
||||||
private static RestfulServer ourListenerRestServer;
|
private static RestfulServer ourListenerRestServer;
|
||||||
private static Server ourListenerServer;
|
private static Server ourListenerServer;
|
||||||
private static String ourListenerServerBase;
|
private static String ourListenerServerBase;
|
||||||
private static List<Observation> ourUpdatedObservations = Lists.newArrayList();
|
private static List<Observation> ourUpdatedObservations = Collections.synchronizedList(Lists.newArrayList());
|
||||||
private static List<String> ourContentTypes = new ArrayList<>();
|
private static List<String> ourContentTypes = Collections.synchronizedList(new ArrayList<>());
|
||||||
private List<IIdType> mySubscriptionIds = new ArrayList<>();
|
private List<IIdType> mySubscriptionIds = Collections.synchronizedList(new ArrayList<>());
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void afterUnregisterRestHookListener() {
|
public void afterUnregisterRestHookListener() {
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
package ca.uhn.fhir.jpa.subscription;
|
package ca.uhn.fhir.jpa.subscription;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
@ -27,6 +26,7 @@ import org.eclipse.jetty.servlet.ServletHolder;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.junit.*;
|
import org.junit.*;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -34,13 +34,13 @@ import java.util.List;
|
||||||
*/
|
*/
|
||||||
public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu2Test extends BaseResourceProviderDstu2Test {
|
public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu2Test extends BaseResourceProviderDstu2Test {
|
||||||
|
|
||||||
private static List<Observation> ourCreatedObservations = Lists.newArrayList();
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RestHookTestWithInterceptorRegisteredToDaoConfigDstu2Test.class);
|
||||||
|
private static List<Observation> ourCreatedObservations = Collections.synchronizedList(Lists.newArrayList());
|
||||||
private static int ourListenerPort;
|
private static int ourListenerPort;
|
||||||
private static RestfulServer ourListenerRestServer;
|
private static RestfulServer ourListenerRestServer;
|
||||||
private static Server ourListenerServer;
|
private static Server ourListenerServer;
|
||||||
private static String ourListenerServerBase;
|
private static String ourListenerServerBase;
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RestHookTestWithInterceptorRegisteredToDaoConfigDstu2Test.class);
|
private static List<Observation> ourUpdatedObservations = Collections.synchronizedList(Lists.newArrayList());
|
||||||
private static List<Observation> ourUpdatedObservations = Lists.newArrayList();
|
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void afterUnregisterRestHookListener() {
|
public void afterUnregisterRestHookListener() {
|
||||||
|
@ -142,7 +142,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu2Test extends B
|
||||||
waitForSize(0, ourCreatedObservations);
|
waitForSize(0, ourCreatedObservations);
|
||||||
waitForSize(3, ourUpdatedObservations);
|
waitForSize(3, ourUpdatedObservations);
|
||||||
|
|
||||||
ourClient.delete().resourceById(new IdDt("Subscription/"+ subscription2.getId())).execute();
|
ourClient.delete().resourceById(new IdDt("Subscription/" + subscription2.getId())).execute();
|
||||||
|
|
||||||
Observation observationTemp3 = sendObservation(code, "SNOMED-CT");
|
Observation observationTemp3 = sendObservation(code, "SNOMED-CT");
|
||||||
|
|
||||||
|
@ -215,7 +215,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu2Test extends B
|
||||||
waitForSize(0, ourCreatedObservations);
|
waitForSize(0, ourCreatedObservations);
|
||||||
waitForSize(3, ourUpdatedObservations);
|
waitForSize(3, ourUpdatedObservations);
|
||||||
|
|
||||||
ourClient.delete().resourceById(new IdDt("Subscription/"+ subscription2.getId())).execute();
|
ourClient.delete().resourceById(new IdDt("Subscription/" + subscription2.getId())).execute();
|
||||||
|
|
||||||
Observation observationTemp3 = sendObservation(code, "SNOMED-CT");
|
Observation observationTemp3 = sendObservation(code, "SNOMED-CT");
|
||||||
|
|
||||||
|
@ -256,6 +256,28 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu2Test extends B
|
||||||
Assert.assertFalse(observation2.getId().isEmpty());
|
Assert.assertFalse(observation2.getId().isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class ObservationListener implements IResourceProvider {
|
||||||
|
|
||||||
|
@Create
|
||||||
|
public MethodOutcome create(@ResourceParam Observation theObservation) {
|
||||||
|
ourLog.info("Received Listener Create");
|
||||||
|
ourCreatedObservations.add(theObservation);
|
||||||
|
return new MethodOutcome(new IdDt("Observation/1"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends IBaseResource> getResourceType() {
|
||||||
|
return Observation.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Update
|
||||||
|
public MethodOutcome update(@ResourceParam Observation theObservation) {
|
||||||
|
ourLog.info("Received Listener Update");
|
||||||
|
ourUpdatedObservations.add(theObservation);
|
||||||
|
return new MethodOutcome(new IdDt("Observation/1"), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void startListenerServer() throws Exception {
|
public static void startListenerServer() throws Exception {
|
||||||
|
@ -284,27 +306,4 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu2Test extends B
|
||||||
ourListenerServer.stop();
|
ourListenerServer.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ObservationListener implements IResourceProvider {
|
|
||||||
|
|
||||||
@Create
|
|
||||||
public MethodOutcome create(@ResourceParam Observation theObservation) {
|
|
||||||
ourLog.info("Received Listener Create");
|
|
||||||
ourCreatedObservations.add(theObservation);
|
|
||||||
return new MethodOutcome(new IdDt("Observation/1"), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Class<? extends IBaseResource> getResourceType() {
|
|
||||||
return Observation.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Update
|
|
||||||
public MethodOutcome update(@ResourceParam Observation theObservation) {
|
|
||||||
ourLog.info("Received Listener Update");
|
|
||||||
ourUpdatedObservations.add(theObservation);
|
|
||||||
return new MethodOutcome(new IdDt("Observation/1"), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package ca.uhn.fhir.jpa.subscription;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.eclipse.jetty.server.Server;
|
import org.eclipse.jetty.server.Server;
|
||||||
|
@ -29,13 +30,13 @@ import ca.uhn.fhir.rest.server.RestfulServer;
|
||||||
*/
|
*/
|
||||||
public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu3Test extends BaseResourceProviderDstu3Test {
|
public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu3Test extends BaseResourceProviderDstu3Test {
|
||||||
|
|
||||||
private static List<Observation> ourCreatedObservations = Lists.newArrayList();
|
private static List<Observation> ourCreatedObservations = Collections.synchronizedList(Lists.newArrayList());
|
||||||
private static int ourListenerPort;
|
private static int ourListenerPort;
|
||||||
private static RestfulServer ourListenerRestServer;
|
private static RestfulServer ourListenerRestServer;
|
||||||
private static Server ourListenerServer;
|
private static Server ourListenerServer;
|
||||||
private static String ourListenerServerBase;
|
private static String ourListenerServerBase;
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RestHookTestWithInterceptorRegisteredToDaoConfigDstu3Test.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RestHookTestWithInterceptorRegisteredToDaoConfigDstu3Test.class);
|
||||||
private static List<Observation> ourUpdatedObservations = Lists.newArrayList();
|
private static List<Observation> ourUpdatedObservations = Collections.synchronizedList(Lists.newArrayList());
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean shouldLogClient() {
|
protected boolean shouldLogClient() {
|
||||||
|
|
|
@ -23,10 +23,12 @@ import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
public class RestHookActivatesPreExistingSubscriptionsR4Test extends BaseResourceProviderR4Test {
|
public class RestHookActivatesPreExistingSubscriptionsR4Test extends BaseResourceProviderR4Test {
|
||||||
|
|
||||||
|
@ -35,9 +37,9 @@ public class RestHookActivatesPreExistingSubscriptionsR4Test extends BaseResourc
|
||||||
private static RestfulServer ourListenerRestServer;
|
private static RestfulServer ourListenerRestServer;
|
||||||
private static String ourListenerServerBase;
|
private static String ourListenerServerBase;
|
||||||
private static Server ourListenerServer;
|
private static Server ourListenerServer;
|
||||||
private static List<Observation> ourUpdatedObservations = Lists.newArrayList();
|
private static List<Observation> ourUpdatedObservations = Collections.synchronizedList(Lists.newArrayList());
|
||||||
private static List<String> ourContentTypes = new ArrayList<>();
|
private static List<String> ourContentTypes = Collections.synchronizedList(new ArrayList<>());
|
||||||
private static List<String> ourHeaders = new ArrayList<>();
|
private static List<String> ourHeaders = Collections.synchronizedList(new ArrayList<>());
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void afterResetSubscriptionActivatingInterceptor() {
|
public void afterResetSubscriptionActivatingInterceptor() {
|
||||||
|
@ -123,33 +125,6 @@ public class RestHookActivatesPreExistingSubscriptionsR4Test extends BaseResourc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@BeforeClass
|
|
||||||
public static void startListenerServer() throws Exception {
|
|
||||||
ourListenerPort = PortUtil.findFreePort();
|
|
||||||
ourListenerRestServer = new RestfulServer(FhirContext.forR4());
|
|
||||||
ourListenerServerBase = "http://localhost:" + ourListenerPort + "/fhir/context";
|
|
||||||
|
|
||||||
ObservationListener obsListener = new ObservationListener();
|
|
||||||
ourListenerRestServer.setResourceProviders(obsListener);
|
|
||||||
|
|
||||||
ourListenerServer = new Server(ourListenerPort);
|
|
||||||
|
|
||||||
ServletContextHandler proxyHandler = new ServletContextHandler();
|
|
||||||
proxyHandler.setContextPath("/");
|
|
||||||
|
|
||||||
ServletHolder servletHolder = new ServletHolder();
|
|
||||||
servletHolder.setServlet(ourListenerRestServer);
|
|
||||||
proxyHandler.addServlet(servletHolder, "/fhir/context/*");
|
|
||||||
|
|
||||||
ourListenerServer.setHandler(proxyHandler);
|
|
||||||
ourListenerServer.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
@AfterClass
|
|
||||||
public static void stopListenerServer() throws Exception {
|
|
||||||
ourListenerServer.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class ObservationListener implements IResourceProvider {
|
public static class ObservationListener implements IResourceProvider {
|
||||||
|
|
||||||
|
|
||||||
|
@ -181,4 +156,31 @@ public class RestHookActivatesPreExistingSubscriptionsR4Test extends BaseResourc
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void startListenerServer() throws Exception {
|
||||||
|
ourListenerPort = PortUtil.findFreePort();
|
||||||
|
ourListenerRestServer = new RestfulServer(FhirContext.forR4());
|
||||||
|
ourListenerServerBase = "http://localhost:" + ourListenerPort + "/fhir/context";
|
||||||
|
|
||||||
|
ObservationListener obsListener = new ObservationListener();
|
||||||
|
ourListenerRestServer.setResourceProviders(obsListener);
|
||||||
|
|
||||||
|
ourListenerServer = new Server(ourListenerPort);
|
||||||
|
|
||||||
|
ServletContextHandler proxyHandler = new ServletContextHandler();
|
||||||
|
proxyHandler.setContextPath("/");
|
||||||
|
|
||||||
|
ServletHolder servletHolder = new ServletHolder();
|
||||||
|
servletHolder.setServlet(ourListenerRestServer);
|
||||||
|
proxyHandler.addServlet(servletHolder, "/fhir/context/*");
|
||||||
|
|
||||||
|
ourListenerServer.setHandler(proxyHandler);
|
||||||
|
ourListenerServer.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void stopListenerServer() throws Exception {
|
||||||
|
ourListenerServer.stop();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ import org.springframework.messaging.support.ExecutorSubscribableChannel;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -41,15 +42,15 @@ import static org.junit.Assert.fail;
|
||||||
public class RestHookTestR4Test extends BaseResourceProviderR4Test {
|
public class RestHookTestR4Test extends BaseResourceProviderR4Test {
|
||||||
|
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RestHookTestDstu2Test.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RestHookTestDstu2Test.class);
|
||||||
private static List<Observation> ourCreatedObservations = Lists.newArrayList();
|
private static List<Observation> ourCreatedObservations = Collections.synchronizedList(Lists.newArrayList());
|
||||||
private static int ourListenerPort;
|
private static int ourListenerPort;
|
||||||
private static RestfulServer ourListenerRestServer;
|
private static RestfulServer ourListenerRestServer;
|
||||||
private static Server ourListenerServer;
|
private static Server ourListenerServer;
|
||||||
private static String ourListenerServerBase;
|
private static String ourListenerServerBase;
|
||||||
private static List<Observation> ourUpdatedObservations = Lists.newArrayList();
|
private static List<Observation> ourUpdatedObservations = Collections.synchronizedList(Lists.newArrayList());
|
||||||
private static List<String> ourContentTypes = new ArrayList<>();
|
private static List<String> ourContentTypes = Collections.synchronizedList(new ArrayList<>());
|
||||||
private static List<String> ourHeaders = new ArrayList<>();
|
private static List<String> ourHeaders = Collections.synchronizedList(new ArrayList<>());
|
||||||
private List<IIdType> mySubscriptionIds = new ArrayList<>();
|
private List<IIdType> mySubscriptionIds = Collections.synchronizedList(new ArrayList<>());
|
||||||
private CountingInterceptor myCountingInterceptor;
|
private CountingInterceptor myCountingInterceptor;
|
||||||
|
|
||||||
@After
|
@After
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
|
|
||||||
package ca.uhn.fhir.jpa.subscription.r4;
|
package ca.uhn.fhir.jpa.subscription.r4;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.eclipse.jetty.server.Server;
|
import org.eclipse.jetty.server.Server;
|
||||||
|
@ -27,13 +28,13 @@ import ca.uhn.fhir.rest.server.RestfulServer;
|
||||||
*/
|
*/
|
||||||
public class RestHookTestWithInterceptorRegisteredToDaoConfigR4Test extends BaseResourceProviderR4Test {
|
public class RestHookTestWithInterceptorRegisteredToDaoConfigR4Test extends BaseResourceProviderR4Test {
|
||||||
|
|
||||||
private static List<Observation> ourCreatedObservations = Lists.newArrayList();
|
private static List<Observation> ourCreatedObservations = Collections.synchronizedList(Lists.newArrayList());
|
||||||
private static int ourListenerPort;
|
private static int ourListenerPort;
|
||||||
private static RestfulServer ourListenerRestServer;
|
private static RestfulServer ourListenerRestServer;
|
||||||
private static Server ourListenerServer;
|
private static Server ourListenerServer;
|
||||||
private static String ourListenerServerBase;
|
private static String ourListenerServerBase;
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RestHookTestWithInterceptorRegisteredToDaoConfigR4Test.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RestHookTestWithInterceptorRegisteredToDaoConfigR4Test.class);
|
||||||
private static List<Observation> ourUpdatedObservations = Lists.newArrayList();
|
private static List<Observation> ourUpdatedObservations = Collections.synchronizedList(Lists.newArrayList());
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean shouldLogClient() {
|
protected boolean shouldLogClient() {
|
||||||
|
|
|
@ -13,6 +13,7 @@ import org.junit.Test;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -35,13 +36,13 @@ import java.util.List;
|
||||||
public class RestHookWithEventDefinitionR4Test extends BaseResourceProviderR4Test {
|
public class RestHookWithEventDefinitionR4Test extends BaseResourceProviderR4Test {
|
||||||
|
|
||||||
private static final Logger ourLog = org.slf4j.LoggerFactory.getLogger(RestHookWithEventDefinitionR4Test.class);
|
private static final Logger ourLog = org.slf4j.LoggerFactory.getLogger(RestHookWithEventDefinitionR4Test.class);
|
||||||
private static List<Observation> ourUpdatedObservations = Lists.newArrayList();
|
private static List<Observation> ourUpdatedObservations = Collections.synchronizedList(Lists.newArrayList());
|
||||||
private static List<String> ourContentTypes = new ArrayList<>();
|
private static List<String> ourContentTypes = Collections.synchronizedList(new ArrayList<>());
|
||||||
private static List<String> ourHeaders = new ArrayList<>();
|
private static List<String> ourHeaders = Collections.synchronizedList(new ArrayList<>());
|
||||||
private static List<Observation> ourCreatedObservations = Lists.newArrayList();
|
private static List<Observation> ourCreatedObservations = Collections.synchronizedList(Lists.newArrayList());
|
||||||
private String myPatientId;
|
private String myPatientId;
|
||||||
private String mySubscriptionId;
|
private String mySubscriptionId;
|
||||||
private List<IIdType> mySubscriptionIds = new ArrayList<>();
|
private List<IIdType> mySubscriptionIds = Collections.synchronizedList(new ArrayList<>());
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@After
|
@After
|
||||||
|
|
|
@ -83,15 +83,12 @@ public class ServerExceptionDstu3Test {
|
||||||
ourException = new InternalErrorException("Error", operationOutcome);
|
ourException = new InternalErrorException("Error", operationOutcome);
|
||||||
|
|
||||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_format=json");
|
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_format=json");
|
||||||
CloseableHttpResponse status = ourClient.execute(httpGet);
|
try (CloseableHttpResponse status = ourClient.execute(httpGet)) {
|
||||||
try {
|
|
||||||
byte[] responseContentBytes = IOUtils.toByteArray(status.getEntity().getContent());
|
byte[] responseContentBytes = IOUtils.toByteArray(status.getEntity().getContent());
|
||||||
String responseContent = new String(responseContentBytes, Charsets.UTF_8);
|
String responseContent = new String(responseContentBytes, Charsets.UTF_8);
|
||||||
ourLog.info(status.getStatusLine().toString());
|
ourLog.info(status.getStatusLine().toString());
|
||||||
ourLog.info(responseContent);
|
ourLog.info(responseContent);
|
||||||
assertThat(responseContent, containsString("El nombre está vacío"));
|
assertThat(responseContent, containsString("El nombre está vacío"));
|
||||||
} finally {
|
|
||||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -105,16 +102,13 @@ public class ServerExceptionDstu3Test {
|
||||||
ourException = new AuthenticationException().addAuthenticateHeaderForRealm("REALM");
|
ourException = new AuthenticationException().addAuthenticateHeaderForRealm("REALM");
|
||||||
|
|
||||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient");
|
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient");
|
||||||
CloseableHttpResponse status = ourClient.execute(httpGet);
|
try (CloseableHttpResponse status = ourClient.execute(httpGet)) {
|
||||||
try {
|
|
||||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||||
ourLog.info(status.getStatusLine().toString());
|
ourLog.info(status.getStatusLine().toString());
|
||||||
ourLog.info(responseContent);
|
ourLog.info(responseContent);
|
||||||
|
|
||||||
assertEquals(401, status.getStatusLine().getStatusCode());
|
assertEquals(401, status.getStatusLine().getStatusCode());
|
||||||
assertEquals("Basic realm=\"REALM\"", status.getFirstHeader("WWW-Authenticate").getValue());
|
assertEquals("Basic realm=\"REALM\"", status.getFirstHeader("WWW-Authenticate").getValue());
|
||||||
} finally {
|
|
||||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
4
pom.xml
4
pom.xml
|
@ -2063,7 +2063,7 @@
|
||||||
</reportsDirectories>
|
</reportsDirectories>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<!--<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-project-info-reports-plugin</artifactId>
|
<artifactId>maven-project-info-reports-plugin</artifactId>
|
||||||
<version>3.0.0</version>
|
<version>3.0.0</version>
|
||||||
|
@ -2078,7 +2078,7 @@
|
||||||
</reports>
|
</reports>
|
||||||
</reportSet>
|
</reportSet>
|
||||||
</reportSets>
|
</reportSets>
|
||||||
</plugin>
|
</plugin>-->
|
||||||
<!-- <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-linkcheck-plugin</artifactId> <version>1.1</version> </plugin> -->
|
<!-- <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-linkcheck-plugin</artifactId> <version>1.1</version> </plugin> -->
|
||||||
</plugins>
|
</plugins>
|
||||||
</reporting>
|
</reporting>
|
||||||
|
|
|
@ -147,6 +147,23 @@
|
||||||
The JPA server version migrator tool now runs in a multithreaded way, allowing it to
|
The JPA server version migrator tool now runs in a multithreaded way, allowing it to
|
||||||
upgrade th database faster when migration tasks require data updates.
|
upgrade th database faster when migration tasks require data updates.
|
||||||
</action>
|
</action>
|
||||||
|
<action type="fix">
|
||||||
|
A bug in the JPA server was fixed: When a resource was previously deleted,
|
||||||
|
a transaction could not be posted that both restored the deleted resource but
|
||||||
|
also contained references to the now-restored resource.
|
||||||
|
</action>
|
||||||
|
<action type="fix">
|
||||||
|
The $expunge operation could sometimes fail to delete resources if a resource
|
||||||
|
to be deleted had recently been returned in a search result. This has been
|
||||||
|
corrected.
|
||||||
|
</action>
|
||||||
|
<action type="add">
|
||||||
|
A new setting has been added to the JPA Server DopConfig that controls the
|
||||||
|
behaviour when a client-assigned ID is encountered (i.e. the client performs
|
||||||
|
an HTTP PUT to a resource ID that doesn't already exist on the server). It is
|
||||||
|
now possible to disallow this action, to only allow alphanumeric IDs (the default
|
||||||
|
and only option previously) or allow any IDs including alphanumeric.
|
||||||
|
</action>
|
||||||
</release>
|
</release>
|
||||||
|
|
||||||
<release version="3.5.0" date="2018-09-17">
|
<release version="3.5.0" date="2018-09-17">
|
||||||
|
|
Loading…
Reference in New Issue