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.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.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.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
|
||||
|
|
|
@ -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.resthook.SubscriptionRestHookInterceptor;
|
||||
import ca.uhn.fhir.jpa.subscription.websocket.SubscriptionWebsocketInterceptor;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
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.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
@ -57,7 +54,6 @@ import org.springframework.scheduling.concurrent.ScheduledExecutorFactoryBean;
|
|||
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
|
||||
|
@ -92,44 +88,7 @@ public abstract class BaseConfig implements SchedulingConfigurer {
|
|||
* factory with HAPI FHIR customizations
|
||||
*/
|
||||
protected LocalContainerEntityManagerFactoryBean entityManagerFactory() {
|
||||
LocalContainerEntityManagerFactoryBean retVal = new 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;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
LocalContainerEntityManagerFactoryBean retVal = new HapiFhirLocalContainerEntityManagerFactoryBean();
|
||||
configureEntityManagerFactory(retVal, fhirContext());
|
||||
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.UUID;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.persistence.EntityManager;
|
||||
|
@ -37,6 +36,7 @@ import javax.persistence.criteria.Root;
|
|||
import javax.xml.stream.events.Characters;
|
||||
import javax.xml.stream.events.XMLEvent;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.data.*;
|
||||
import org.apache.commons.lang3.NotImplementedException;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
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.RuntimeResourceDefinition;
|
||||
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.ResourceIndexedSearchParams;
|
||||
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.InvalidRequestException;
|
||||
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.ResourceVersionConflictException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
|
@ -261,6 +245,8 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao,
|
|||
protected EntityManager myEntityManager;
|
||||
@Autowired
|
||||
protected IForcedIdDao myForcedIdDao;
|
||||
@Autowired
|
||||
protected ISearchResultDao mySearchResultDao;
|
||||
@Autowired(required = false)
|
||||
protected IFulltextSearchSvc myFulltextSearchSvc;
|
||||
@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()) {
|
||||
if (isValidPid(theId)) {
|
||||
return;
|
||||
/**
|
||||
* Returns the newly created forced ID. If the entity already had a forced ID, or if
|
||||
* none was created, returns null.
|
||||
*/
|
||||
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();
|
||||
|
@ -330,7 +320,10 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao,
|
|||
fid.setForcedId(theId.getIdPart());
|
||||
fid.setResource(theEntity);
|
||||
theEntity.setForcedId(fid);
|
||||
return fid;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
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
|
||||
*/
|
||||
|
@ -416,6 +419,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao,
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
for (Long next : historicalIds) {
|
||||
txTemplate.execute(t -> {
|
||||
expungeHistoricalVersion(next);
|
||||
|
@ -675,6 +679,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao,
|
|||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DaoConfig getConfig() {
|
||||
return myConfig;
|
||||
}
|
||||
|
@ -705,6 +710,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao,
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <R extends IBaseResource> IFhirResourceDao<R> getDao(Class<R> theType) {
|
||||
Map<Class<? extends IBaseResource>, IFhirResourceDao<?>> resourceTypeToDao = getDaos();
|
||||
|
@ -886,6 +892,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao,
|
|||
theProvider.setSearchCoordinatorSvc(mySearchCoordinatorSvc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLogicalReference(IIdType theId) {
|
||||
Set<String> treatReferencesAsLogical = myConfig.getTreatReferencesAsLogical();
|
||||
if (treatReferencesAsLogical != null) {
|
||||
|
@ -1461,11 +1468,11 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao,
|
|||
|
||||
@Override
|
||||
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) {
|
||||
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
|
||||
theResourceId, IBaseResource theOldResource) {
|
||||
// Notify interceptors
|
||||
ActionRequestDetails requestDetails = null;
|
||||
ActionRequestDetails requestDetails;
|
||||
if (theRequestDetails != null) {
|
||||
requestDetails = new ActionRequestDetails(theRequestDetails, theResource, theResourceId.getResourceType(), theResourceId);
|
||||
notifyInterceptors(RestOperationTypeEnum.UPDATE, requestDetails);
|
||||
|
@ -1988,15 +1995,15 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao,
|
|||
return retVal;
|
||||
}
|
||||
|
||||
protected static Long translateForcedIdToPid(String theResourceName, String theResourceId, IForcedIdDao
|
||||
protected static Long translateForcedIdToPid(DaoConfig theDaoConfig, String theResourceName, String theResourceId, IForcedIdDao
|
||||
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());
|
||||
|
||||
if (isValidPid(theId)) {
|
||||
if (theDaoConfig.getResourceClientIdStrategy() != DaoConfig.ClientIdStrategyEnum.ANY && isValidPid(theId)) {
|
||||
return Collections.singletonList(theId.getIdPartAsLong());
|
||||
} else {
|
||||
List<ForcedId> forcedId;
|
||||
|
|
|
@ -53,16 +53,12 @@ import org.hl7.fhir.instance.model.api.*;
|
|||
import org.hl7.fhir.r4.model.InstantType;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Required;
|
||||
import org.springframework.lang.NonNull;
|
||||
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.annotation.Nonnull;
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.persistence.NoResultException;
|
||||
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 (isValidPid(theResource.getIdElement())) {
|
||||
throw new UnprocessableEntityException(
|
||||
"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");
|
||||
switch (myDaoConfig.getResourceClientIdStrategy()) {
|
||||
case NOT_ALLOWED:
|
||||
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
|
||||
|
@ -413,8 +423,21 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
|
||||
// Perform actual DB update
|
||||
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),
|
||||
|
@ -1231,10 +1254,6 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
try {
|
||||
entity = readEntityLatestVersion(resourceId);
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
|
@ -1325,12 +1344,14 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
|
||||
private void validateGivenIdIsAppropriateToRetrieveResource(IIdType theId, BaseHasResource entity) {
|
||||
if (entity.getForcedId() != null) {
|
||||
if (theId.isIdPartValidLong()) {
|
||||
// This means that the resource with the given numeric ID exists, but it has a "forced ID", meaning that
|
||||
// as far as the outside world is concerned, the given ID doesn't exist (it's just an internal pointer
|
||||
// to the
|
||||
// forced ID)
|
||||
throw new ResourceNotFoundException(theId);
|
||||
if (myDaoConfig.getResourceClientIdStrategy() != DaoConfig.ClientIdStrategyEnum.ANY) {
|
||||
if (theId.isIdPartValidLong()) {
|
||||
// This means that the resource with the given numeric ID exists, but it has a "forced ID", meaning that
|
||||
// as far as the outside world is concerned, the given ID doesn't exist (it's just an internal pointer
|
||||
// to the
|
||||
// forced ID)
|
||||
throw new ResourceNotFoundException(theId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -156,6 +156,7 @@ public class DaoConfig {
|
|||
private List<Integer> mySearchPreFetchThresholds = Arrays.asList(500, 2000, -1);
|
||||
private List<WarmCacheEntry> myWarmCacheEntries = new ArrayList<>();
|
||||
private boolean myDisableHashBasedSearches;
|
||||
private ClientIdStrategyEnum myResourceClientIdStrategy = ClientIdStrategyEnum.ALPHANUMERIC;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
|
@ -642,9 +643,39 @@ public class DaoConfig {
|
|||
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
|
||||
* 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() {
|
||||
return myResourceServerIdStrategy;
|
||||
|
@ -653,8 +684,13 @@ public class DaoConfig {
|
|||
/**
|
||||
* This setting configures the strategy to use in generating IDs for newly
|
||||
* 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) {
|
||||
Validate.notNull(theResourceIdStrategy, "theResourceIdStrategy must not be null");
|
||||
|
@ -1353,18 +1389,8 @@ public class DaoConfig {
|
|||
* given number.
|
||||
* </p>
|
||||
*/
|
||||
public void setSearchPreFetchThresholds(List<Integer> thePreFetchThresholds) {
|
||||
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;
|
||||
public List<Integer> getSearchPreFetchThresholds() {
|
||||
return mySearchPreFetchThresholds;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1380,8 +1406,18 @@ public class DaoConfig {
|
|||
* given number.
|
||||
* </p>
|
||||
*/
|
||||
public List<Integer> getSearchPreFetchThresholds() {
|
||||
return mySearchPreFetchThresholds;
|
||||
public void setSearchPreFetchThresholds(List<Integer> thePreFetchThresholds) {
|
||||
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
|
||||
}
|
||||
|
||||
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) {
|
||||
Validate.notBlank(theUrl, "Base URL must not be null or empty");
|
||||
|
||||
|
|
|
@ -67,6 +67,9 @@ public class FulltextSearchSvcImpl implements IFulltextSearchSvc {
|
|||
|
||||
private Boolean ourDisabled;
|
||||
|
||||
@Autowired
|
||||
private DaoConfig myDaoConfig;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
|
@ -222,7 +225,7 @@ public class FulltextSearchSvcImpl implements IFulltextSearchSvc {
|
|||
StringParam idParm = (StringParam) idParam;
|
||||
idParamValue = idParm.getValue();
|
||||
}
|
||||
pid = BaseHapiFhirDao.translateForcedIdToPid(theResourceName, idParamValue, myForcedIdDao);
|
||||
pid = BaseHapiFhirDao.translateForcedIdToPid(myDaoConfig, theResourceName, idParamValue, myForcedIdDao);
|
||||
}
|
||||
|
||||
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) {
|
||||
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);
|
||||
|
||||
|
|
|
@ -1600,7 +1600,7 @@ public class SearchBuilder implements ISearchBuilder {
|
|||
|
||||
if (myParams.get(IAnyResource.SP_RES_ID) != null) {
|
||||
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) {
|
||||
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")
|
||||
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")
|
||||
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")
|
||||
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
|
||||
@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")
|
||||
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
|
||||
@Query("DELETE FROM SearchResult s WHERE s.myId IN :ids")
|
||||
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
|
||||
* least one pass even if one is half finished
|
||||
*/
|
||||
Integer forceReindexingPass();
|
||||
int forceReindexingPass();
|
||||
|
||||
/**
|
||||
* Cancels all running and future reindexing jobs. This is mainly intended
|
||||
|
|
|
@ -196,7 +196,7 @@ public class ResourceReindexingSvcImpl implements IResourceReindexingSvc {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Integer forceReindexingPass() {
|
||||
public int forceReindexingPass() {
|
||||
myIndexingLock.lock();
|
||||
try {
|
||||
return doReindexingPassInsideLock();
|
||||
|
@ -219,7 +219,7 @@ public class ResourceReindexingSvcImpl implements IResourceReindexingSvc {
|
|||
expungeJobsMarkedAsDeleted();
|
||||
}
|
||||
|
||||
private Integer runReindexJobs() {
|
||||
private int runReindexJobs() {
|
||||
Collection<ResourceReindexJobEntity> jobs = myTxTemplate.execute(t -> myReindexJobDao.findAll(PageRequest.of(0, 10), false));
|
||||
assert jobs != null;
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ public class FhirResourceDaoR4CodeSystemTest extends BaseJpaR4Test {
|
|||
myCodeSystemDao.create(cs, mySrd);
|
||||
|
||||
myResourceReindexingSvc.markAllResourcesForReindexing();
|
||||
int outcome = myResourceReindexingSvc.runReindexingPass();
|
||||
int outcome = myResourceReindexingSvc.forceReindexingPass();
|
||||
assertNotEquals(-1, outcome); // -1 means there was a failure
|
||||
|
||||
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.SearchParameterMap;
|
||||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||
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.r4.model.*;
|
||||
import org.junit.After;
|
||||
|
@ -11,12 +13,14 @@ import org.junit.AfterClass;
|
|||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class FhirResourceDaoR4CreateTest extends BaseJpaR4Test {
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(FhirResourceDaoR4CreateTest.class);
|
||||
|
@ -24,6 +28,7 @@ public class FhirResourceDaoR4CreateTest extends BaseJpaR4Test {
|
|||
@After
|
||||
public void afterResetDao() {
|
||||
myDaoConfig.setResourceServerIdStrategy(new DaoConfig().getResourceServerIdStrategy());
|
||||
myDaoConfig.setResourceClientIdStrategy(new DaoConfig().getResourceClientIdStrategy());
|
||||
}
|
||||
|
||||
@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
|
||||
public void testTransactionCreateWithUuidResourceStrategy() {
|
||||
myDaoConfig.setResourceServerIdStrategy(DaoConfig.IdStrategyEnum.UUID);
|
||||
|
|
|
@ -146,8 +146,8 @@ public class FhirResourceDaoR4SearchCustomSearchParamTest extends BaseJpaR4Test
|
|||
|
||||
mySearchParameterDao.create(fooSp, mySrd);
|
||||
|
||||
assertEquals(1, myResourceReindexingSvc.forceReindexingPass().intValue());
|
||||
assertEquals(0, myResourceReindexingSvc.forceReindexingPass().intValue());
|
||||
assertEquals(1, myResourceReindexingSvc.forceReindexingPass());
|
||||
assertEquals(0, myResourceReindexingSvc.forceReindexingPass());
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -182,7 +182,7 @@ public class FhirResourceDaoR4Test extends BaseJpaR4Test {
|
|||
});
|
||||
|
||||
myResourceReindexingSvc.markAllResourcesForReindexing();
|
||||
myResourceReindexingSvc.runReindexingPass();
|
||||
myResourceReindexingSvc.forceReindexingPass();
|
||||
|
||||
runInTransaction(() -> {
|
||||
Optional<ResourceTable> tableOpt = myResourceTableDao.findById(id1.getIdPartAsLong());
|
||||
|
@ -225,7 +225,7 @@ public class FhirResourceDaoR4Test extends BaseJpaR4Test {
|
|||
});
|
||||
|
||||
myResourceReindexingSvc.markAllResourcesForReindexing();
|
||||
myResourceReindexingSvc.runReindexingPass();
|
||||
myResourceReindexingSvc.forceReindexingPass();
|
||||
|
||||
runInTransaction(() -> {
|
||||
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.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.dao.data.IForcedIdDao;
|
||||
import ca.uhn.fhir.jpa.dao.data.IResourceHistoryTableDao;
|
||||
import ca.uhn.fhir.jpa.dao.data.IResourceTableDao;
|
||||
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
|
||||
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.ResourceGoneException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||
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.r4.model.IdType;
|
||||
import org.hl7.fhir.r4.model.Observation;
|
||||
|
@ -19,7 +18,8 @@ import org.junit.After;
|
|||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
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.not;
|
||||
|
@ -168,17 +168,17 @@ public class ExpungeR4Test extends BaseResourceProviderR4Test {
|
|||
myPatientDao.update(p).getId();
|
||||
myPatientDao.delete(new IdType("Patient/TEST"));
|
||||
|
||||
runInTransaction(()-> assertThat(myResourceTableDao.findAll(), not(empty())));
|
||||
runInTransaction(()-> assertThat(myResourceHistoryTableDao.findAll(), not(empty())));
|
||||
runInTransaction(()-> assertThat(myForcedIdDao.findAll(), not(empty())));
|
||||
runInTransaction(() -> assertThat(myResourceTableDao.findAll(), not(empty())));
|
||||
runInTransaction(() -> assertThat(myResourceHistoryTableDao.findAll(), not(empty())));
|
||||
runInTransaction(() -> assertThat(myForcedIdDao.findAll(), not(empty())));
|
||||
|
||||
myPatientDao.expunge(new ExpungeOptions()
|
||||
.setExpungeDeletedResources(true)
|
||||
.setExpungeOldVersions(true));
|
||||
|
||||
runInTransaction(()-> assertThat(myResourceTableDao.findAll(), empty()));
|
||||
runInTransaction(()-> assertThat(myResourceHistoryTableDao.findAll(), empty()));
|
||||
runInTransaction(()-> assertThat(myForcedIdDao.findAll(), empty()));
|
||||
runInTransaction(() -> assertThat(myResourceTableDao.findAll(), empty()));
|
||||
runInTransaction(() -> assertThat(myResourceHistoryTableDao.findAll(), empty()));
|
||||
runInTransaction(() -> assertThat(myForcedIdDao.findAll(), empty()));
|
||||
|
||||
}
|
||||
|
||||
|
@ -332,6 +332,61 @@ public class ExpungeR4Test extends BaseResourceProviderR4Test {
|
|||
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
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
|
|
|
@ -24,6 +24,7 @@ import org.junit.*;
|
|||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
@ -35,14 +36,14 @@ import static org.junit.Assert.fail;
|
|||
public class RestHookTestDstu3Test extends BaseResourceProviderDstu3Test {
|
||||
|
||||
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 RestfulServer ourListenerRestServer;
|
||||
private static Server ourListenerServer;
|
||||
private static String ourListenerServerBase;
|
||||
private static List<Observation> ourUpdatedObservations = Lists.newArrayList();
|
||||
private static List<String> ourContentTypes = new ArrayList<>();
|
||||
private List<IIdType> mySubscriptionIds = new ArrayList<>();
|
||||
private static List<Observation> ourUpdatedObservations = Collections.synchronizedList(Lists.newArrayList());
|
||||
private static List<String> ourContentTypes = Collections.synchronizedList(new ArrayList<>());
|
||||
private List<IIdType> mySubscriptionIds = Collections.synchronizedList(new ArrayList<>());
|
||||
|
||||
@After
|
||||
public void afterUnregisterRestHookListener() {
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
package ca.uhn.fhir.jpa.subscription;
|
||||
|
||||
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.junit.*;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
|
@ -34,13 +34,13 @@ import java.util.List;
|
|||
*/
|
||||
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 RestfulServer ourListenerRestServer;
|
||||
private static Server ourListenerServer;
|
||||
private static String ourListenerServerBase;
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RestHookTestWithInterceptorRegisteredToDaoConfigDstu2Test.class);
|
||||
private static List<Observation> ourUpdatedObservations = Lists.newArrayList();
|
||||
private static List<Observation> ourUpdatedObservations = Collections.synchronizedList(Lists.newArrayList());
|
||||
|
||||
@After
|
||||
public void afterUnregisterRestHookListener() {
|
||||
|
@ -142,7 +142,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu2Test extends B
|
|||
waitForSize(0, ourCreatedObservations);
|
||||
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");
|
||||
|
||||
|
@ -215,7 +215,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu2Test extends B
|
|||
waitForSize(0, ourCreatedObservations);
|
||||
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");
|
||||
|
||||
|
@ -256,6 +256,28 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu2Test extends B
|
|||
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
|
||||
public static void startListenerServer() throws Exception {
|
||||
|
@ -284,27 +306,4 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu2Test extends B
|
|||
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 java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.server.Server;
|
||||
|
@ -29,13 +30,13 @@ import ca.uhn.fhir.rest.server.RestfulServer;
|
|||
*/
|
||||
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 RestfulServer ourListenerRestServer;
|
||||
private static Server ourListenerServer;
|
||||
private static String ourListenerServerBase;
|
||||
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
|
||||
protected boolean shouldLogClient() {
|
||||
|
|
|
@ -23,10 +23,12 @@ import org.slf4j.LoggerFactory;
|
|||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
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 {
|
||||
|
||||
|
@ -35,9 +37,9 @@ public class RestHookActivatesPreExistingSubscriptionsR4Test extends BaseResourc
|
|||
private static RestfulServer ourListenerRestServer;
|
||||
private static String ourListenerServerBase;
|
||||
private static Server ourListenerServer;
|
||||
private static List<Observation> ourUpdatedObservations = Lists.newArrayList();
|
||||
private static List<String> ourContentTypes = new ArrayList<>();
|
||||
private static List<String> ourHeaders = new ArrayList<>();
|
||||
private static List<Observation> ourUpdatedObservations = Collections.synchronizedList(Lists.newArrayList());
|
||||
private static List<String> ourContentTypes = Collections.synchronizedList(new ArrayList<>());
|
||||
private static List<String> ourHeaders = Collections.synchronizedList(new ArrayList<>());
|
||||
|
||||
@After
|
||||
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 {
|
||||
|
||||
|
||||
|
@ -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 java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -41,15 +42,15 @@ import static org.junit.Assert.fail;
|
|||
public class RestHookTestR4Test extends BaseResourceProviderR4Test {
|
||||
|
||||
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 RestfulServer ourListenerRestServer;
|
||||
private static Server ourListenerServer;
|
||||
private static String ourListenerServerBase;
|
||||
private static List<Observation> ourUpdatedObservations = Lists.newArrayList();
|
||||
private static List<String> ourContentTypes = new ArrayList<>();
|
||||
private static List<String> ourHeaders = new ArrayList<>();
|
||||
private List<IIdType> mySubscriptionIds = new ArrayList<>();
|
||||
private static List<Observation> ourUpdatedObservations = Collections.synchronizedList(Lists.newArrayList());
|
||||
private static List<String> ourContentTypes = Collections.synchronizedList(new ArrayList<>());
|
||||
private static List<String> ourHeaders = Collections.synchronizedList(new ArrayList<>());
|
||||
private List<IIdType> mySubscriptionIds = Collections.synchronizedList(new ArrayList<>());
|
||||
private CountingInterceptor myCountingInterceptor;
|
||||
|
||||
@After
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
|
||||
package ca.uhn.fhir.jpa.subscription.r4;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.server.Server;
|
||||
|
@ -27,13 +28,13 @@ import ca.uhn.fhir.rest.server.RestfulServer;
|
|||
*/
|
||||
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 RestfulServer ourListenerRestServer;
|
||||
private static Server ourListenerServer;
|
||||
private static String ourListenerServerBase;
|
||||
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
|
||||
protected boolean shouldLogClient() {
|
||||
|
|
|
@ -13,6 +13,7 @@ import org.junit.Test;
|
|||
import org.slf4j.Logger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
|
@ -35,13 +36,13 @@ import java.util.List;
|
|||
public class RestHookWithEventDefinitionR4Test extends BaseResourceProviderR4Test {
|
||||
|
||||
private static final Logger ourLog = org.slf4j.LoggerFactory.getLogger(RestHookWithEventDefinitionR4Test.class);
|
||||
private static List<Observation> ourUpdatedObservations = Lists.newArrayList();
|
||||
private static List<String> ourContentTypes = new ArrayList<>();
|
||||
private static List<String> ourHeaders = new ArrayList<>();
|
||||
private static List<Observation> ourCreatedObservations = Lists.newArrayList();
|
||||
private static List<Observation> ourUpdatedObservations = Collections.synchronizedList(Lists.newArrayList());
|
||||
private static List<String> ourContentTypes = Collections.synchronizedList(new ArrayList<>());
|
||||
private static List<String> ourHeaders = Collections.synchronizedList(new ArrayList<>());
|
||||
private static List<Observation> ourCreatedObservations = Collections.synchronizedList(Lists.newArrayList());
|
||||
private String myPatientId;
|
||||
private String mySubscriptionId;
|
||||
private List<IIdType> mySubscriptionIds = new ArrayList<>();
|
||||
private List<IIdType> mySubscriptionIds = Collections.synchronizedList(new ArrayList<>());
|
||||
|
||||
@Override
|
||||
@After
|
||||
|
|
|
@ -83,15 +83,12 @@ public class ServerExceptionDstu3Test {
|
|||
ourException = new InternalErrorException("Error", operationOutcome);
|
||||
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_format=json");
|
||||
CloseableHttpResponse status = ourClient.execute(httpGet);
|
||||
try {
|
||||
try (CloseableHttpResponse status = ourClient.execute(httpGet)) {
|
||||
byte[] responseContentBytes = IOUtils.toByteArray(status.getEntity().getContent());
|
||||
String responseContent = new String(responseContentBytes, Charsets.UTF_8);
|
||||
ourLog.info(status.getStatusLine().toString());
|
||||
ourLog.info(responseContent);
|
||||
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");
|
||||
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient");
|
||||
CloseableHttpResponse status = ourClient.execute(httpGet);
|
||||
try {
|
||||
try (CloseableHttpResponse status = ourClient.execute(httpGet)) {
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(status.getStatusLine().toString());
|
||||
ourLog.info(responseContent);
|
||||
|
||||
assertEquals(401, status.getStatusLine().getStatusCode());
|
||||
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>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<!--<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-project-info-reports-plugin</artifactId>
|
||||
<version>3.0.0</version>
|
||||
|
@ -2078,7 +2078,7 @@
|
|||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
</plugin>-->
|
||||
<!-- <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-linkcheck-plugin</artifactId> <version>1.1</version> </plugin> -->
|
||||
</plugins>
|
||||
</reporting>
|
||||
|
|
|
@ -147,6 +147,23 @@
|
|||
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.
|
||||
</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 version="3.5.0" date="2018-09-17">
|
||||
|
|
Loading…
Reference in New Issue