Merge branch 'philips-3.6.0'
This commit is contained in:
commit
b44e96a5cd
|
@ -25,6 +25,8 @@ import ca.uhn.fhir.i18n.HapiLocalizer;
|
||||||
import ca.uhn.fhir.jpa.dao.DaoRegistry;
|
import ca.uhn.fhir.jpa.dao.DaoRegistry;
|
||||||
import ca.uhn.fhir.jpa.provider.SubscriptionTriggeringProvider;
|
import ca.uhn.fhir.jpa.provider.SubscriptionTriggeringProvider;
|
||||||
import ca.uhn.fhir.jpa.search.*;
|
import ca.uhn.fhir.jpa.search.*;
|
||||||
|
import ca.uhn.fhir.jpa.search.warm.CacheWarmingSvcImpl;
|
||||||
|
import ca.uhn.fhir.jpa.search.warm.ICacheWarmingSvc;
|
||||||
import ca.uhn.fhir.jpa.sp.ISearchParamPresenceSvc;
|
import ca.uhn.fhir.jpa.sp.ISearchParamPresenceSvc;
|
||||||
import ca.uhn.fhir.jpa.sp.SearchParamPresenceSvcImpl;
|
import ca.uhn.fhir.jpa.sp.SearchParamPresenceSvcImpl;
|
||||||
import ca.uhn.fhir.jpa.subscription.email.SubscriptionEmailInterceptor;
|
import ca.uhn.fhir.jpa.subscription.email.SubscriptionEmailInterceptor;
|
||||||
|
@ -32,7 +34,10 @@ 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 ca.uhn.fhir.jpa.util.IReindexController;
|
import ca.uhn.fhir.jpa.util.IReindexController;
|
||||||
import ca.uhn.fhir.jpa.util.ReindexController;
|
import ca.uhn.fhir.jpa.util.ReindexController;
|
||||||
|
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;
|
||||||
|
@ -52,6 +57,7 @@ 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;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
|
@ -85,13 +91,33 @@ 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 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
};
|
||||||
configureEntityManagerFactory(retVal, fhirContext());
|
configureEntityManagerFactory(retVal, fhirContext());
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract FhirContext fhirContext();
|
public abstract FhirContext fhirContext();
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ICacheWarmingSvc cacheWarmingSvc() {
|
||||||
|
return new CacheWarmingSvcImpl();
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public HibernateExceptionTranslator hibernateExceptionTranslator() {
|
public HibernateExceptionTranslator hibernateExceptionTranslator() {
|
||||||
return new HibernateExceptionTranslator();
|
return new HibernateExceptionTranslator();
|
||||||
|
|
|
@ -511,9 +511,13 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
@Override
|
@Override
|
||||||
@Transactional(propagation = Propagation.NEVER)
|
@Transactional(propagation = Propagation.NEVER)
|
||||||
public ExpungeOutcome expunge(IIdType theId, ExpungeOptions theExpungeOptions) {
|
public ExpungeOutcome expunge(IIdType theId, ExpungeOptions theExpungeOptions) {
|
||||||
BaseHasResource entity = readEntity(theId);
|
|
||||||
|
TransactionTemplate txTemplate = new TransactionTemplate(myPlatformTransactionManager);
|
||||||
|
|
||||||
|
BaseHasResource entity = txTemplate.execute(t->readEntity(theId));
|
||||||
if (theId.hasVersionIdPart()) {
|
if (theId.hasVersionIdPart()) {
|
||||||
BaseHasResource currentVersion = readEntity(theId.toVersionless());
|
BaseHasResource currentVersion;
|
||||||
|
currentVersion = txTemplate.execute(t->readEntity(theId.toVersionless()));
|
||||||
if (entity.getVersion() == currentVersion.getVersion()) {
|
if (entity.getVersion() == currentVersion.getVersion()) {
|
||||||
throw new PreconditionFailedException("Can not perform version-specific expunge of resource " + theId.toUnqualified().getValue() + " as this is the current version");
|
throw new PreconditionFailedException("Can not perform version-specific expunge of resource " + theId.toUnqualified().getValue() + " as this is the current version");
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,9 +24,9 @@ import ca.uhn.fhir.context.FhirContext;
|
||||||
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.search.JpaRuntimeSearchParam;
|
import ca.uhn.fhir.jpa.search.JpaRuntimeSearchParam;
|
||||||
import ca.uhn.fhir.util.StopWatch;
|
|
||||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||||
import ca.uhn.fhir.util.SearchParameterUtil;
|
import ca.uhn.fhir.util.SearchParameterUtil;
|
||||||
|
import ca.uhn.fhir.util.StopWatch;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.commons.lang3.time.DateUtils;
|
import org.apache.commons.lang3.time.DateUtils;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
@ -37,6 +37,8 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.ApplicationContextAware;
|
import org.springframework.context.ApplicationContextAware;
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.transaction.PlatformTransactionManager;
|
||||||
|
import org.springframework.transaction.support.TransactionTemplate;
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
@ -58,7 +60,8 @@ public abstract class BaseSearchParamRegistry<SP extends IBaseResource> implemen
|
||||||
private DaoConfig myDaoConfig;
|
private DaoConfig myDaoConfig;
|
||||||
private volatile long myLastRefresh;
|
private volatile long myLastRefresh;
|
||||||
private ApplicationContext myApplicationContext;
|
private ApplicationContext myApplicationContext;
|
||||||
|
@Autowired
|
||||||
|
private PlatformTransactionManager myTxManager;
|
||||||
public BaseSearchParamRegistry() {
|
public BaseSearchParamRegistry() {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
@ -197,7 +200,7 @@ public abstract class BaseSearchParamRegistry<SP extends IBaseResource> implemen
|
||||||
});
|
});
|
||||||
for (String nextBase : next.getBase()) {
|
for (String nextBase : next.getBase()) {
|
||||||
if (!activeParamNamesToUniqueSearchParams.containsKey(nextBase)) {
|
if (!activeParamNamesToUniqueSearchParams.containsKey(nextBase)) {
|
||||||
activeParamNamesToUniqueSearchParams.put(nextBase, new HashMap<Set<String>, List<JpaRuntimeSearchParam>>());
|
activeParamNamesToUniqueSearchParams.put(nextBase, new HashMap<>());
|
||||||
}
|
}
|
||||||
if (!activeParamNamesToUniqueSearchParams.get(nextBase).containsKey(paramNames)) {
|
if (!activeParamNamesToUniqueSearchParams.get(nextBase).containsKey(paramNames)) {
|
||||||
activeParamNamesToUniqueSearchParams.get(nextBase).put(paramNames, new ArrayList<JpaRuntimeSearchParam>());
|
activeParamNamesToUniqueSearchParams.get(nextBase).put(paramNames, new ArrayList<JpaRuntimeSearchParam>());
|
||||||
|
@ -242,7 +245,17 @@ public abstract class BaseSearchParamRegistry<SP extends IBaseResource> implemen
|
||||||
long refreshInterval = 60 * DateUtils.MILLIS_PER_MINUTE;
|
long refreshInterval = 60 * DateUtils.MILLIS_PER_MINUTE;
|
||||||
if (System.currentTimeMillis() - refreshInterval > myLastRefresh) {
|
if (System.currentTimeMillis() - refreshInterval > myLastRefresh) {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
if (System.currentTimeMillis() - refreshInterval > myLastRefresh) {
|
TransactionTemplate txTemplate = new TransactionTemplate(myTxManager);
|
||||||
|
txTemplate.execute(t->{
|
||||||
|
doRefresh(refreshInterval);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doRefresh(long theRefreshInterval) {
|
||||||
|
if (System.currentTimeMillis() - theRefreshInterval > myLastRefresh) {
|
||||||
StopWatch sw = new StopWatch();
|
StopWatch sw = new StopWatch();
|
||||||
|
|
||||||
Map<String, Map<String, RuntimeSearchParam>> searchParams = new HashMap<>();
|
Map<String, Map<String, RuntimeSearchParam>> searchParams = new HashMap<>();
|
||||||
|
@ -322,8 +335,6 @@ public abstract class BaseSearchParamRegistry<SP extends IBaseResource> implemen
|
||||||
ourLog.info("Refreshed search parameter cache in {}ms", sw.getMillis());
|
ourLog.info("Refreshed search parameter cache in {}ms", sw.getMillis());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Scheduled(fixedDelay = 10 * DateUtils.MILLIS_PER_SECOND)
|
@Scheduled(fixedDelay = 10 * DateUtils.MILLIS_PER_SECOND)
|
||||||
public void refreshCacheOnSchedule() {
|
public void refreshCacheOnSchedule() {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package ca.uhn.fhir.jpa.dao;
|
package ca.uhn.fhir.jpa.dao;
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.entity.ResourceEncodingEnum;
|
import ca.uhn.fhir.jpa.entity.ResourceEncodingEnum;
|
||||||
|
import ca.uhn.fhir.jpa.search.warm.WarmCacheEntry;
|
||||||
import ca.uhn.fhir.jpa.util.JpaConstants;
|
import ca.uhn.fhir.jpa.util.JpaConstants;
|
||||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
|
@ -152,7 +153,8 @@ public class DaoConfig {
|
||||||
private int myReindexThreadCount;
|
private int myReindexThreadCount;
|
||||||
private Set<String> myBundleTypesAllowedForStorage;
|
private Set<String> myBundleTypesAllowedForStorage;
|
||||||
private boolean myValidateSearchParameterExpressionsOnSave = true;
|
private boolean myValidateSearchParameterExpressionsOnSave = true;
|
||||||
private List<Integer> myPreFetchThresholds = Arrays.asList(500, 2000, -1);
|
private List<Integer> mySearchPreFetchThresholds = Arrays.asList(500, 2000, -1);
|
||||||
|
private List<WarmCacheEntry> myWarmCacheEntries = new ArrayList<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
|
@ -171,6 +173,22 @@ public class DaoConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a set of searches that should be kept "warm", meaning that
|
||||||
|
* searches will periodically be performed in the background to
|
||||||
|
* keep results ready for this search
|
||||||
|
*/
|
||||||
|
public List<WarmCacheEntry> getWarmCacheEntries() {
|
||||||
|
if (myWarmCacheEntries == null) {
|
||||||
|
myWarmCacheEntries = new ArrayList<>();
|
||||||
|
}
|
||||||
|
return myWarmCacheEntries;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWarmCacheEntries(List<WarmCacheEntry> theWarmCacheEntries) {
|
||||||
|
myWarmCacheEntries = theWarmCacheEntries;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If set to <code>true</code> (default is false), the reindexing of search parameters
|
* If set to <code>true</code> (default is false), the reindexing of search parameters
|
||||||
* using a query on the HFJ_RESOURCE.SP_INDEX_STATUS column will be disabled completely.
|
* using a query on the HFJ_RESOURCE.SP_INDEX_STATUS column will be disabled completely.
|
||||||
|
@ -496,18 +514,18 @@ public class DaoConfig {
|
||||||
/**
|
/**
|
||||||
* This may be used to optionally register server interceptors directly against the DAOs.
|
* This may be used to optionally register server interceptors directly against the DAOs.
|
||||||
*/
|
*/
|
||||||
public void setInterceptors(IServerInterceptor... theInterceptor) {
|
public void setInterceptors(List<IServerInterceptor> theInterceptors) {
|
||||||
setInterceptors(new ArrayList<IServerInterceptor>());
|
myInterceptors = theInterceptors;
|
||||||
if (theInterceptor != null && theInterceptor.length != 0) {
|
|
||||||
getInterceptors().addAll(Arrays.asList(theInterceptor));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This may be used to optionally register server interceptors directly against the DAOs.
|
* This may be used to optionally register server interceptors directly against the DAOs.
|
||||||
*/
|
*/
|
||||||
public void setInterceptors(List<IServerInterceptor> theInterceptors) {
|
public void setInterceptors(IServerInterceptor... theInterceptor) {
|
||||||
myInterceptors = theInterceptors;
|
setInterceptors(new ArrayList<IServerInterceptor>());
|
||||||
|
if (theInterceptor != null && theInterceptor.length != 0) {
|
||||||
|
getInterceptors().addAll(Arrays.asList(theInterceptor));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1345,7 +1363,7 @@ public class DaoConfig {
|
||||||
Validate.isTrue(last != -1, "Prefetch thresholds must be sequential");
|
Validate.isTrue(last != -1, "Prefetch thresholds must be sequential");
|
||||||
last = nextInt;
|
last = nextInt;
|
||||||
}
|
}
|
||||||
myPreFetchThresholds = thePreFetchThresholds;
|
mySearchPreFetchThresholds = thePreFetchThresholds;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1361,8 +1379,8 @@ public class DaoConfig {
|
||||||
* given number.
|
* given number.
|
||||||
* </p>
|
* </p>
|
||||||
*/
|
*/
|
||||||
public List<Integer> getPreFetchThresholds() {
|
public List<Integer> getSearchPreFetchThresholds() {
|
||||||
return myPreFetchThresholds;
|
return mySearchPreFetchThresholds;
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum IndexEnabledEnum {
|
public enum IndexEnabledEnum {
|
||||||
|
|
|
@ -23,4 +23,7 @@ package ca.uhn.fhir.jpa.dao;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
public interface IResultIterator extends Iterator<Long> {
|
public interface IResultIterator extends Iterator<Long> {
|
||||||
|
|
||||||
|
int getSkippedCount();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1359,6 +1359,8 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
private TypedQuery<Long> createQuery(SortSpec sort, Integer theMaximumResults, boolean theCount) {
|
private TypedQuery<Long> createQuery(SortSpec sort, Integer theMaximumResults, boolean theCount) {
|
||||||
|
myPredicates = new ArrayList<>();
|
||||||
|
|
||||||
CriteriaQuery<Long> outerQuery;
|
CriteriaQuery<Long> outerQuery;
|
||||||
/*
|
/*
|
||||||
* Sort
|
* Sort
|
||||||
|
@ -1369,30 +1371,48 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
if (sort != null) {
|
if (sort != null) {
|
||||||
assert !theCount;
|
assert !theCount;
|
||||||
|
|
||||||
|
// outerQuery = myBuilder.createQuery(Long.class);
|
||||||
|
// Root<ResourceTable> outerQueryFrom = outerQuery.from(ResourceTable.class);
|
||||||
|
//
|
||||||
|
// List<Order> orders = Lists.newArrayList();
|
||||||
|
// List<Predicate> predicates = Lists.newArrayList();
|
||||||
|
//
|
||||||
|
// createSort(myBuilder, outerQueryFrom, sort, orders, predicates);
|
||||||
|
// if (orders.size() > 0) {
|
||||||
|
// outerQuery.orderBy(orders);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Subquery<Long> subQ = outerQuery.subquery(Long.class);
|
||||||
|
// Root<ResourceTable> subQfrom = subQ.from(ResourceTable.class);
|
||||||
|
//
|
||||||
|
// myResourceTableQuery = subQ;
|
||||||
|
// myResourceTableRoot = subQfrom;
|
||||||
|
//
|
||||||
|
// Expression<Long> selectExpr = subQfrom.get("myId").as(Long.class);
|
||||||
|
// subQ.select(selectExpr);
|
||||||
|
//
|
||||||
|
// predicates.add(0, myBuilder.in(outerQueryFrom.get("myId").as(Long.class)).value(subQ));
|
||||||
|
//
|
||||||
|
// outerQuery.multiselect(outerQueryFrom.get("myId").as(Long.class));
|
||||||
|
// outerQuery.where(predicates.toArray(new Predicate[0]));
|
||||||
|
|
||||||
outerQuery = myBuilder.createQuery(Long.class);
|
outerQuery = myBuilder.createQuery(Long.class);
|
||||||
Root<ResourceTable> outerQueryFrom = outerQuery.from(ResourceTable.class);
|
myResourceTableQuery = outerQuery;
|
||||||
|
myResourceTableRoot = myResourceTableQuery.from(ResourceTable.class);
|
||||||
|
if (theCount) {
|
||||||
|
outerQuery.multiselect(myBuilder.countDistinct(myResourceTableRoot));
|
||||||
|
} else {
|
||||||
|
outerQuery.multiselect(myResourceTableRoot.get("myId").as(Long.class));
|
||||||
|
}
|
||||||
|
|
||||||
List<Order> orders = Lists.newArrayList();
|
List<Order> orders = Lists.newArrayList();
|
||||||
List<Predicate> predicates = Lists.newArrayList();
|
List<Predicate> predicates = myPredicates; // Lists.newArrayList();
|
||||||
|
|
||||||
createSort(myBuilder, outerQueryFrom, sort, orders, predicates);
|
createSort(myBuilder, myResourceTableRoot, sort, orders, predicates);
|
||||||
if (orders.size() > 0) {
|
if (orders.size() > 0) {
|
||||||
outerQuery.orderBy(orders);
|
outerQuery.orderBy(orders);
|
||||||
}
|
}
|
||||||
|
|
||||||
Subquery<Long> subQ = outerQuery.subquery(Long.class);
|
|
||||||
Root<ResourceTable> subQfrom = subQ.from(ResourceTable.class);
|
|
||||||
|
|
||||||
myResourceTableQuery = subQ;
|
|
||||||
myResourceTableRoot = subQfrom;
|
|
||||||
|
|
||||||
Expression<Long> selectExpr = subQfrom.get("myId").as(Long.class);
|
|
||||||
subQ.select(selectExpr);
|
|
||||||
|
|
||||||
predicates.add(0, myBuilder.in(outerQueryFrom.get("myId").as(Long.class)).value(subQ));
|
|
||||||
|
|
||||||
outerQuery.multiselect(outerQueryFrom.get("myId").as(Long.class));
|
|
||||||
outerQuery.where(predicates.toArray(new Predicate[0]));
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
@ -1407,8 +1427,6 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
myPredicates = new ArrayList<>();
|
|
||||||
|
|
||||||
if (myParams.getEverythingMode() != null) {
|
if (myParams.getEverythingMode() != null) {
|
||||||
Join<ResourceTable, ResourceLink> join = myResourceTableRoot.join("myResourceLinks", JoinType.LEFT);
|
Join<ResourceTable, ResourceLink> join = myResourceTableRoot.join("myResourceLinks", JoinType.LEFT);
|
||||||
|
|
||||||
|
@ -1590,7 +1608,8 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
if (param.getParamType() == RestSearchParameterTypeEnum.REFERENCE) {
|
if (param.getParamType() == RestSearchParameterTypeEnum.REFERENCE) {
|
||||||
thePredicates.add(join.get("mySourcePath").as(String.class).in(param.getPathsSplit()));
|
thePredicates.add(join.get("mySourcePath").as(String.class).in(param.getPathsSplit()));
|
||||||
} else {
|
} else {
|
||||||
Predicate joinParam1 = theBuilder.equal(join.get("myParamName"), theSort.getParamName());
|
Long hashIdentity = BaseResourceIndexedSearchParam.calculateHashIdentity(myResourceName, theSort.getParamName());
|
||||||
|
Predicate joinParam1 = theBuilder.equal(join.get("myHashIdentity"), hashIdentity);
|
||||||
thePredicates.add(joinParam1);
|
thePredicates.add(joinParam1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -1760,7 +1779,8 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* THIS SHOULD RETURN HASHSET and not just Set because we add to it later (so it can't be Collections.emptySet())
|
* THIS SHOULD RETURN HASHSET and not just Set because we add to it later
|
||||||
|
* so it can't be Collections.emptySet() or some such thing
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public HashSet<Long> loadIncludes(IDao theCallingDao, FhirContext theContext, EntityManager theEntityManager, Collection<Long> theMatches, Set<Include> theRevIncludes,
|
public HashSet<Long> loadIncludes(IDao theCallingDao, FhirContext theContext, EntityManager theEntityManager, Collection<Long> theMatches, Set<Include> theRevIncludes,
|
||||||
|
@ -1940,11 +1960,11 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (theParamName.equals(BaseResource.SP_RES_ID)) {
|
if (theParamName.equals(IAnyResource.SP_RES_ID)) {
|
||||||
|
|
||||||
addPredicateResourceId(theAndOrParams);
|
addPredicateResourceId(theAndOrParams);
|
||||||
|
|
||||||
} else if (theParamName.equals(BaseResource.SP_RES_LANGUAGE)) {
|
} else if (theParamName.equals(IAnyResource.SP_RES_LANGUAGE)) {
|
||||||
|
|
||||||
addPredicateLanguage(theAndOrParams);
|
addPredicateLanguage(theAndOrParams);
|
||||||
|
|
||||||
|
@ -2154,6 +2174,7 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
private SortSpec mySort;
|
private SortSpec mySort;
|
||||||
private boolean myStillNeedToFetchIncludes;
|
private boolean myStillNeedToFetchIncludes;
|
||||||
private StopWatch myStopwatch = null;
|
private StopWatch myStopwatch = null;
|
||||||
|
private int mySkipCount = 0;
|
||||||
|
|
||||||
private QueryIterator() {
|
private QueryIterator() {
|
||||||
mySort = myParams.getSort();
|
mySort = myParams.getSort();
|
||||||
|
@ -2193,9 +2214,12 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
if (myPreResultsIterator != null && myPreResultsIterator.hasNext()) {
|
if (myPreResultsIterator != null && myPreResultsIterator.hasNext()) {
|
||||||
while (myPreResultsIterator.hasNext()) {
|
while (myPreResultsIterator.hasNext()) {
|
||||||
Long next = myPreResultsIterator.next();
|
Long next = myPreResultsIterator.next();
|
||||||
if (next != null && myPidSet.add(next)) {
|
if (next != null)
|
||||||
|
if (myPidSet.add(next)) {
|
||||||
myNext = next;
|
myNext = next;
|
||||||
break;
|
break;
|
||||||
|
} else {
|
||||||
|
mySkipCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2203,9 +2227,12 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
if (myNext == null) {
|
if (myNext == null) {
|
||||||
while (myResultsIterator.hasNext()) {
|
while (myResultsIterator.hasNext()) {
|
||||||
Long next = myResultsIterator.next();
|
Long next = myResultsIterator.next();
|
||||||
if (next != null && myPidSet.add(next)) {
|
if (next != null)
|
||||||
|
if (myPidSet.add(next)) {
|
||||||
myNext = next;
|
myNext = next;
|
||||||
break;
|
break;
|
||||||
|
} else {
|
||||||
|
mySkipCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2218,9 +2245,12 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
if (myIncludesIterator != null) {
|
if (myIncludesIterator != null) {
|
||||||
while (myIncludesIterator.hasNext()) {
|
while (myIncludesIterator.hasNext()) {
|
||||||
Long next = myIncludesIterator.next();
|
Long next = myIncludesIterator.next();
|
||||||
if (next != null && myPidSet.add(next)) {
|
if (next != null)
|
||||||
|
if (myPidSet.add(next)) {
|
||||||
myNext = next;
|
myNext = next;
|
||||||
break;
|
break;
|
||||||
|
} else {
|
||||||
|
mySkipCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (myNext == null) {
|
if (myNext == null) {
|
||||||
|
@ -2260,6 +2290,11 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
Validate.isTrue(retVal != NO_MORE, "No more elements");
|
Validate.isTrue(retVal != NO_MORE, "No more elements");
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSkippedCount() {
|
||||||
|
return mySkipCount;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class UniqueIndexIterator implements IResultIterator {
|
private class UniqueIndexIterator implements IResultIterator {
|
||||||
|
@ -2296,6 +2331,11 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
public void remove() {
|
public void remove() {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSkippedCount() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class CountQueryIterator implements Iterator<Long> {
|
private static class CountQueryIterator implements Iterator<Long> {
|
||||||
|
|
|
@ -44,6 +44,10 @@ import static org.apache.commons.lang3.StringUtils.left;
|
||||||
* do not reuse these names:
|
* do not reuse these names:
|
||||||
* IDX_SP_STRING
|
* IDX_SP_STRING
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// This one us used only for sorting
|
||||||
|
@Index(name = "IDX_SP_STRING_HASH_IDENT", columnList = "HASH_IDENTITY"),
|
||||||
|
|
||||||
@Index(name = "IDX_SP_STRING_HASH_NRM", columnList = "HASH_NORM_PREFIX,SP_VALUE_NORMALIZED"),
|
@Index(name = "IDX_SP_STRING_HASH_NRM", columnList = "HASH_NORM_PREFIX,SP_VALUE_NORMALIZED"),
|
||||||
@Index(name = "IDX_SP_STRING_HASH_EXCT", columnList = "HASH_EXACT"),
|
@Index(name = "IDX_SP_STRING_HASH_EXCT", columnList = "HASH_EXACT"),
|
||||||
|
|
||||||
|
@ -130,6 +134,11 @@ public class ResourceIndexedSearchParamString extends BaseResourceIndexedSearchP
|
||||||
*/
|
*/
|
||||||
@Column(name = "HASH_NORM_PREFIX", nullable = true)
|
@Column(name = "HASH_NORM_PREFIX", nullable = true)
|
||||||
private Long myHashNormalizedPrefix;
|
private Long myHashNormalizedPrefix;
|
||||||
|
/**
|
||||||
|
* @since 3.6.0 - At some point this should be made not-null
|
||||||
|
*/
|
||||||
|
@Column(name = "HASH_IDENTITY", nullable = true)
|
||||||
|
private Long myHashIdentity;
|
||||||
/**
|
/**
|
||||||
* @since 3.4.0 - At some point this should be made not-null
|
* @since 3.4.0 - At some point this should be made not-null
|
||||||
*/
|
*/
|
||||||
|
@ -137,12 +146,10 @@ public class ResourceIndexedSearchParamString extends BaseResourceIndexedSearchP
|
||||||
private Long myHashExact;
|
private Long myHashExact;
|
||||||
@Transient
|
@Transient
|
||||||
private transient DaoConfig myDaoConfig;
|
private transient DaoConfig myDaoConfig;
|
||||||
|
|
||||||
public ResourceIndexedSearchParamString() {
|
public ResourceIndexedSearchParamString() {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public ResourceIndexedSearchParamString(DaoConfig theDaoConfig, String theName, String theValueNormalized, String theValueExact) {
|
public ResourceIndexedSearchParamString(DaoConfig theDaoConfig, String theName, String theValueNormalized, String theValueExact) {
|
||||||
setDaoConfig(theDaoConfig);
|
setDaoConfig(theDaoConfig);
|
||||||
setParamName(theName);
|
setParamName(theName);
|
||||||
|
@ -150,6 +157,10 @@ public class ResourceIndexedSearchParamString extends BaseResourceIndexedSearchP
|
||||||
setValueExact(theValueExact);
|
setValueExact(theValueExact);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setHashIdentity(Long theHashIdentity) {
|
||||||
|
myHashIdentity = theHashIdentity;
|
||||||
|
}
|
||||||
|
|
||||||
@PrePersist
|
@PrePersist
|
||||||
public void calculateHashes() {
|
public void calculateHashes() {
|
||||||
if (myHashNormalizedPrefix == null && myDaoConfig != null) {
|
if (myHashNormalizedPrefix == null && myDaoConfig != null) {
|
||||||
|
@ -159,6 +170,7 @@ public class ResourceIndexedSearchParamString extends BaseResourceIndexedSearchP
|
||||||
String valueExact = getValueExact();
|
String valueExact = getValueExact();
|
||||||
setHashNormalizedPrefix(calculateHashNormalized(myDaoConfig, resourceType, paramName, valueNormalized));
|
setHashNormalizedPrefix(calculateHashNormalized(myDaoConfig, resourceType, paramName, valueNormalized));
|
||||||
setHashExact(calculateHashExact(resourceType, paramName, valueExact));
|
setHashExact(calculateHashExact(resourceType, paramName, valueExact));
|
||||||
|
setHashIdentity(calculateHashIdentity(resourceType, paramName));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,6 @@ import ca.uhn.fhir.model.api.Include;
|
||||||
import ca.uhn.fhir.rest.param.DateRangeParam;
|
import ca.uhn.fhir.rest.param.DateRangeParam;
|
||||||
import org.apache.commons.lang3.SerializationUtils;
|
import org.apache.commons.lang3.SerializationUtils;
|
||||||
import org.hibernate.annotations.OptimisticLock;
|
import org.hibernate.annotations.OptimisticLock;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import javax.persistence.*;
|
import javax.persistence.*;
|
||||||
import javax.validation.constraints.NotNull;
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
|
@ -111,8 +111,9 @@ public class SearchParamPresent implements Serializable {
|
||||||
return b.build();
|
return b.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static long calculateHashPresence(String theResourceType, String theParamName, boolean thePresent) {
|
public static long calculateHashPresence(String theResourceType, String theParamName, Boolean thePresent) {
|
||||||
return BaseResourceIndexedSearchParam.hash(theResourceType, theParamName, Boolean.toString(thePresent));
|
String string = thePresent != null ? Boolean.toString(thePresent) : Boolean.toString(false);
|
||||||
|
return BaseResourceIndexedSearchParam.hash(theResourceType, theParamName, string);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,10 +24,15 @@ import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.jpa.dao.IDao;
|
import ca.uhn.fhir.jpa.dao.IDao;
|
||||||
import ca.uhn.fhir.jpa.dao.ISearchBuilder;
|
import ca.uhn.fhir.jpa.dao.ISearchBuilder;
|
||||||
import ca.uhn.fhir.jpa.dao.data.ISearchDao;
|
import ca.uhn.fhir.jpa.dao.data.ISearchDao;
|
||||||
import ca.uhn.fhir.jpa.entity.*;
|
import ca.uhn.fhir.jpa.entity.BaseHasResource;
|
||||||
|
import ca.uhn.fhir.jpa.entity.ResourceHistoryTable;
|
||||||
|
import ca.uhn.fhir.jpa.entity.Search;
|
||||||
|
import ca.uhn.fhir.jpa.entity.SearchTypeEnum;
|
||||||
import ca.uhn.fhir.model.primitive.InstantDt;
|
import ca.uhn.fhir.model.primitive.InstantDt;
|
||||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
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.TransactionStatus;
|
||||||
|
@ -46,6 +51,7 @@ import java.util.*;
|
||||||
|
|
||||||
public class PersistedJpaBundleProvider implements IBundleProvider {
|
public class PersistedJpaBundleProvider implements IBundleProvider {
|
||||||
|
|
||||||
|
private static final Logger ourLog = LoggerFactory.getLogger(PersistedJpaBundleProvider.class);
|
||||||
private FhirContext myContext;
|
private FhirContext myContext;
|
||||||
private IDao myDao;
|
private IDao myDao;
|
||||||
private EntityManager myEntityManager;
|
private EntityManager myEntityManager;
|
||||||
|
@ -149,11 +155,10 @@ public class PersistedJpaBundleProvider implements IBundleProvider {
|
||||||
if (mySearchEntity == null) {
|
if (mySearchEntity == null) {
|
||||||
ensureDependenciesInjected();
|
ensureDependenciesInjected();
|
||||||
|
|
||||||
TransactionTemplate template = new TransactionTemplate(myPlatformTransactionManager);
|
TransactionTemplate txTemplate = new TransactionTemplate(myPlatformTransactionManager);
|
||||||
template.setPropagationBehavior(TransactionTemplate.PROPAGATION_REQUIRED);
|
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
|
||||||
return template.execute(new TransactionCallback<Boolean>() {
|
txTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_UNCOMMITTED);
|
||||||
@Override
|
return txTemplate.execute(s -> {
|
||||||
public Boolean doInTransaction(TransactionStatus theStatus) {
|
|
||||||
try {
|
try {
|
||||||
setSearchEntity(mySearchDao.findByUuid(myUuid));
|
setSearchEntity(mySearchDao.findByUuid(myUuid));
|
||||||
|
|
||||||
|
@ -161,6 +166,8 @@ public class PersistedJpaBundleProvider implements IBundleProvider {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ourLog.trace("Retrieved search with version {} and total {}", mySearchEntity.getVersion(), mySearchEntity.getTotalCount());
|
||||||
|
|
||||||
// Load the includes now so that they are available outside of this transaction
|
// Load the includes now so that they are available outside of this transaction
|
||||||
mySearchEntity.getIncludes().size();
|
mySearchEntity.getIncludes().size();
|
||||||
|
|
||||||
|
@ -168,7 +175,6 @@ public class PersistedJpaBundleProvider implements IBundleProvider {
|
||||||
} catch (NoResultException e) {
|
} catch (NoResultException e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -46,9 +46,7 @@ import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||||
import org.apache.commons.lang3.time.DateUtils;
|
import org.apache.commons.lang3.time.DateUtils;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.*;
|
||||||
import org.springframework.data.domain.PageRequest;
|
|
||||||
import org.springframework.data.domain.Pageable;
|
|
||||||
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;
|
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;
|
||||||
import org.springframework.transaction.PlatformTransactionManager;
|
import org.springframework.transaction.PlatformTransactionManager;
|
||||||
import org.springframework.transaction.TransactionDefinition;
|
import org.springframework.transaction.TransactionDefinition;
|
||||||
|
@ -360,7 +358,7 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
||||||
PersistedJpaSearchFirstPageBundleProvider retVal = new PersistedJpaSearchFirstPageBundleProvider(search, theCallingDao, task, sb, myManagedTxManager);
|
PersistedJpaSearchFirstPageBundleProvider retVal = new PersistedJpaSearchFirstPageBundleProvider(search, theCallingDao, task, sb, myManagedTxManager);
|
||||||
populateBundleProvider(retVal);
|
populateBundleProvider(retVal);
|
||||||
|
|
||||||
ourLog.info("Search initial phase completed in {}ms", w.getMillis());
|
ourLog.debug("Search initial phase completed in {}ms", w.getMillis());
|
||||||
return retVal;
|
return retVal;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -421,41 +419,39 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract class BaseTask implements Callable<Void> {
|
public abstract class BaseTask implements Callable<Void> {
|
||||||
protected Search getSearch() {
|
|
||||||
return getSearch;
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Search getSearch;
|
|
||||||
private final SearchParameterMap myParams;
|
private final SearchParameterMap myParams;
|
||||||
private final IDao myCallingDao;
|
private final IDao myCallingDao;
|
||||||
private final String myResourceType;
|
private final String myResourceType;
|
||||||
private final ArrayList<Long> mySyncedPids = new ArrayList<>();
|
private final ArrayList<Long> mySyncedPids = new ArrayList<>();
|
||||||
|
|
||||||
protected CountDownLatch getInitialCollectionLatch() {
|
|
||||||
return myInitialCollectionLatch;
|
|
||||||
}
|
|
||||||
|
|
||||||
private final CountDownLatch myInitialCollectionLatch = new CountDownLatch(1);
|
private final CountDownLatch myInitialCollectionLatch = new CountDownLatch(1);
|
||||||
private final CountDownLatch myCompletionLatch;
|
private final CountDownLatch myCompletionLatch;
|
||||||
private final ArrayList<Long> myUnsyncedPids = new ArrayList<>();
|
private final ArrayList<Long> myUnsyncedPids = new ArrayList<>();
|
||||||
|
private Search mySearch;
|
||||||
private boolean myAbortRequested;
|
private boolean myAbortRequested;
|
||||||
private int myCountSaved = 0;
|
private int myCountSaved = 0;
|
||||||
private boolean myAdditionalPrefetchThresholdsRemaining;
|
private boolean myAdditionalPrefetchThresholdsRemaining;
|
||||||
private List<Long> myPreviouslyAddedResourcePids;
|
private List<Long> myPreviouslyAddedResourcePids;
|
||||||
private Integer myMaxResultsToFetch;
|
private Integer myMaxResultsToFetch;
|
||||||
private int myCountFetchedDuringThisPass;
|
private int myCountFetchedDuringThisPass;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
protected BaseTask(Search theSearch, IDao theCallingDao, SearchParameterMap theParams, String theResourceType) {
|
protected BaseTask(Search theSearch, IDao theCallingDao, SearchParameterMap theParams, String theResourceType) {
|
||||||
getSearch = theSearch;
|
mySearch = theSearch;
|
||||||
myCallingDao = theCallingDao;
|
myCallingDao = theCallingDao;
|
||||||
myParams = theParams;
|
myParams = theParams;
|
||||||
myResourceType = theResourceType;
|
myResourceType = theResourceType;
|
||||||
myCompletionLatch = new CountDownLatch(1);
|
myCompletionLatch = new CountDownLatch(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected Search getSearch() {
|
||||||
|
return mySearch;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected CountDownLatch getInitialCollectionLatch() {
|
||||||
|
return myInitialCollectionLatch;
|
||||||
|
}
|
||||||
|
|
||||||
protected void setPreviouslyAddedResourcePids(List<Long> thePreviouslyAddedResourcePids) {
|
protected void setPreviouslyAddedResourcePids(List<Long> thePreviouslyAddedResourcePids) {
|
||||||
myPreviouslyAddedResourcePids = thePreviouslyAddedResourcePids;
|
myPreviouslyAddedResourcePids = thePreviouslyAddedResourcePids;
|
||||||
myCountSaved = myPreviouslyAddedResourcePids.size();
|
myCountSaved = myPreviouslyAddedResourcePids.size();
|
||||||
|
@ -475,8 +471,8 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
||||||
boolean keepWaiting;
|
boolean keepWaiting;
|
||||||
do {
|
do {
|
||||||
synchronized (mySyncedPids) {
|
synchronized (mySyncedPids) {
|
||||||
ourLog.trace("Search status is {}", getSearch.getStatus());
|
ourLog.trace("Search status is {}", mySearch.getStatus());
|
||||||
keepWaiting = mySyncedPids.size() < theToIndex && getSearch.getStatus() == SearchStatusEnum.LOADING;
|
keepWaiting = mySyncedPids.size() < theToIndex && mySearch.getStatus() == SearchStatusEnum.LOADING;
|
||||||
}
|
}
|
||||||
if (keepWaiting) {
|
if (keepWaiting) {
|
||||||
ourLog.info("Waiting, as we only have {} results", mySyncedPids.size());
|
ourLog.info("Waiting, as we only have {} results", mySyncedPids.size());
|
||||||
|
@ -492,7 +488,7 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
||||||
|
|
||||||
ArrayList<Long> retVal = new ArrayList<>();
|
ArrayList<Long> retVal = new ArrayList<>();
|
||||||
synchronized (mySyncedPids) {
|
synchronized (mySyncedPids) {
|
||||||
verifySearchHasntFailedOrThrowInternalErrorException(getSearch);
|
verifySearchHasntFailedOrThrowInternalErrorException(mySearch);
|
||||||
|
|
||||||
int toIndex = theToIndex;
|
int toIndex = theToIndex;
|
||||||
if (mySyncedPids.size() < toIndex) {
|
if (mySyncedPids.size() < toIndex) {
|
||||||
|
@ -520,19 +516,19 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void saveUnsynced(final Iterator<Long> theResultIter) {
|
private void saveUnsynced(final IResultIterator theResultIter) {
|
||||||
TransactionTemplate txTemplate = new TransactionTemplate(myManagedTxManager);
|
TransactionTemplate txTemplate = new TransactionTemplate(myManagedTxManager);
|
||||||
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
|
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
|
||||||
txTemplate.execute(new TransactionCallbackWithoutResult() {
|
txTemplate.execute(new TransactionCallbackWithoutResult() {
|
||||||
@Override
|
@Override
|
||||||
protected void doInTransactionWithoutResult(TransactionStatus theArg0) {
|
protected void doInTransactionWithoutResult(TransactionStatus theArg0) {
|
||||||
if (getSearch.getId() == null) {
|
if (mySearch.getId() == null) {
|
||||||
doSaveSearch();
|
doSaveSearch();
|
||||||
}
|
}
|
||||||
|
|
||||||
List<SearchResult> resultsToSave = Lists.newArrayList();
|
List<SearchResult> resultsToSave = Lists.newArrayList();
|
||||||
for (Long nextPid : myUnsyncedPids) {
|
for (Long nextPid : myUnsyncedPids) {
|
||||||
SearchResult nextResult = new SearchResult(getSearch);
|
SearchResult nextResult = new SearchResult(mySearch);
|
||||||
nextResult.setResourcePid(nextPid);
|
nextResult.setResourcePid(nextPid);
|
||||||
nextResult.setOrder(myCountSaved++);
|
nextResult.setOrder(myCountSaved++);
|
||||||
resultsToSave.add(nextResult);
|
resultsToSave.add(nextResult);
|
||||||
|
@ -547,22 +543,23 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
||||||
myUnsyncedPids.clear();
|
myUnsyncedPids.clear();
|
||||||
|
|
||||||
if (theResultIter.hasNext() == false) {
|
if (theResultIter.hasNext() == false) {
|
||||||
getSearch.setNumFound(myCountSaved);
|
mySearch.setNumFound(myCountSaved);
|
||||||
if (myMaxResultsToFetch != null && myCountSaved < myMaxResultsToFetch) {
|
int loadedCountThisPass = theResultIter.getSkippedCount() + myCountSaved;
|
||||||
getSearch.setStatus(SearchStatusEnum.FINISHED);
|
if (myMaxResultsToFetch != null && loadedCountThisPass < myMaxResultsToFetch) {
|
||||||
getSearch.setTotalCount(myCountSaved);
|
mySearch.setStatus(SearchStatusEnum.FINISHED);
|
||||||
|
mySearch.setTotalCount(myCountSaved);
|
||||||
} else if (myAdditionalPrefetchThresholdsRemaining) {
|
} else if (myAdditionalPrefetchThresholdsRemaining) {
|
||||||
ourLog.trace("Setting search status to PASSCMPLET");
|
ourLog.trace("Setting search status to PASSCMPLET");
|
||||||
getSearch.setStatus(SearchStatusEnum.PASSCMPLET);
|
mySearch.setStatus(SearchStatusEnum.PASSCMPLET);
|
||||||
getSearch.setSearchParameterMap(myParams);
|
mySearch.setSearchParameterMap(myParams);
|
||||||
} else {
|
} else {
|
||||||
getSearch.setStatus(SearchStatusEnum.FINISHED);
|
mySearch.setStatus(SearchStatusEnum.FINISHED);
|
||||||
getSearch.setTotalCount(myCountSaved);
|
mySearch.setTotalCount(myCountSaved);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getSearch.setNumFound(myCountSaved);
|
mySearch.setNumFound(myCountSaved);
|
||||||
|
|
||||||
int numSynced;
|
int numSynced;
|
||||||
synchronized (mySyncedPids) {
|
synchronized (mySyncedPids) {
|
||||||
|
@ -615,6 +612,7 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
||||||
|
|
||||||
TransactionTemplate txTemplate = new TransactionTemplate(myManagedTxManager);
|
TransactionTemplate txTemplate = new TransactionTemplate(myManagedTxManager);
|
||||||
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
|
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
|
||||||
|
txTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_UNCOMMITTED);
|
||||||
txTemplate.execute(new TransactionCallbackWithoutResult() {
|
txTemplate.execute(new TransactionCallbackWithoutResult() {
|
||||||
@Override
|
@Override
|
||||||
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
|
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
|
||||||
|
@ -622,7 +620,7 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
ourLog.info("Completed search for [{}] and found {} resources in {}ms", getSearch.getSearchQueryString(), mySyncedPids.size(), sw.getMillis());
|
ourLog.info("Completed search for [{}{}] and found {} resources in {}ms", mySearch.getResourceType(), mySearch.getSearchQueryString(), mySyncedPids.size(), sw.getMillis());
|
||||||
|
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
|
|
||||||
|
@ -655,15 +653,15 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
||||||
failureCode = ((BaseServerResponseException) t).getStatusCode();
|
failureCode = ((BaseServerResponseException) t).getStatusCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
getSearch.setFailureMessage(failureMessage);
|
mySearch.setFailureMessage(failureMessage);
|
||||||
getSearch.setFailureCode(failureCode);
|
mySearch.setFailureCode(failureCode);
|
||||||
getSearch.setStatus(SearchStatusEnum.FAILED);
|
mySearch.setStatus(SearchStatusEnum.FAILED);
|
||||||
|
|
||||||
saveSearch();
|
saveSearch();
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
|
|
||||||
myIdToSearchTask.remove(getSearch.getUuid());
|
myIdToSearchTask.remove(mySearch.getUuid());
|
||||||
myInitialCollectionLatch.countDown();
|
myInitialCollectionLatch.countDown();
|
||||||
markComplete();
|
markComplete();
|
||||||
|
|
||||||
|
@ -672,13 +670,21 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doSaveSearch() {
|
private void doSaveSearch() {
|
||||||
if (getSearch.getId() == null) {
|
|
||||||
mySearchDao.save(getSearch);
|
Search newSearch;
|
||||||
for (SearchInclude next : getSearch.getIncludes()) {
|
if (mySearch.getId() == null) {
|
||||||
|
newSearch = mySearchDao.save(mySearch);
|
||||||
|
for (SearchInclude next : mySearch.getIncludes()) {
|
||||||
mySearchIncludeDao.save(next);
|
mySearchIncludeDao.save(next);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mySearchDao.save(getSearch);
|
newSearch = mySearchDao.save(mySearch);
|
||||||
|
}
|
||||||
|
|
||||||
|
// mySearchDao.save is not supposed to return null, but in unit tests
|
||||||
|
// it can if the mock search dao isn't set up to handle that
|
||||||
|
if (newSearch != null) {
|
||||||
|
mySearch = newSearch;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -698,20 +704,22 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
||||||
boolean wantCount = myParams.getSummaryMode().contains(SummaryEnum.COUNT);
|
boolean wantCount = myParams.getSummaryMode().contains(SummaryEnum.COUNT);
|
||||||
boolean wantOnlyCount = wantCount && myParams.getSummaryMode().size() == 1;
|
boolean wantOnlyCount = wantCount && myParams.getSummaryMode().size() == 1;
|
||||||
if (wantCount) {
|
if (wantCount) {
|
||||||
|
ourLog.trace("Performing count");
|
||||||
ISearchBuilder sb = newSearchBuilder();
|
ISearchBuilder sb = newSearchBuilder();
|
||||||
Iterator<Long> countIterator = sb.createCountQuery(myParams, getSearch.getUuid());
|
Iterator<Long> countIterator = sb.createCountQuery(myParams, mySearch.getUuid());
|
||||||
Long count = countIterator.next();
|
Long count = countIterator.next();
|
||||||
|
ourLog.trace("Got count {}", count);
|
||||||
|
|
||||||
TransactionTemplate txTemplate = new TransactionTemplate(myManagedTxManager);
|
TransactionTemplate txTemplate = new TransactionTemplate(myManagedTxManager);
|
||||||
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
|
|
||||||
txTemplate.execute(new TransactionCallbackWithoutResult() {
|
txTemplate.execute(new TransactionCallbackWithoutResult() {
|
||||||
@Override
|
@Override
|
||||||
protected void doInTransactionWithoutResult(TransactionStatus theArg0) {
|
protected void doInTransactionWithoutResult(TransactionStatus theArg0) {
|
||||||
getSearch.setTotalCount(count.intValue());
|
mySearch.setTotalCount(count.intValue());
|
||||||
if (wantOnlyCount) {
|
if (wantOnlyCount) {
|
||||||
getSearch.setStatus(SearchStatusEnum.FINISHED);
|
mySearch.setStatus(SearchStatusEnum.FINISHED);
|
||||||
}
|
}
|
||||||
doSaveSearch();
|
doSaveSearch();
|
||||||
|
mySearchDao.flush();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (wantOnlyCount) {
|
if (wantOnlyCount) {
|
||||||
|
@ -719,15 +727,16 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ourLog.trace("Done count");
|
||||||
ISearchBuilder sb = newSearchBuilder();
|
ISearchBuilder sb = newSearchBuilder();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Figure out how many results we're actually going to fetch from the
|
* Figure out how many results we're actually going to fetch from the
|
||||||
* database in this pass. This calculation takes into consideration the
|
* database in this pass. This calculation takes into consideration the
|
||||||
* "pre-fetch thresholds" specified in DaoConfig#getPreFetchThresholds()
|
* "pre-fetch thresholds" specified in DaoConfig#getSearchPreFetchThresholds()
|
||||||
* as well as the value of the _count parameter.
|
* as well as the value of the _count parameter.
|
||||||
*/
|
*/
|
||||||
int currentlyLoaded = defaultIfNull(getSearch.getNumFound(), 0);
|
int currentlyLoaded = defaultIfNull(mySearch.getNumFound(), 0);
|
||||||
int minWanted = 0;
|
int minWanted = 0;
|
||||||
if (myParams.getCount() != null) {
|
if (myParams.getCount() != null) {
|
||||||
minWanted = myParams.getCount();
|
minWanted = myParams.getCount();
|
||||||
|
@ -735,7 +744,7 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
||||||
minWanted += currentlyLoaded;
|
minWanted += currentlyLoaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Iterator<Integer> iter = myDaoConfig.getPreFetchThresholds().iterator(); iter.hasNext(); ) {
|
for (Iterator<Integer> iter = myDaoConfig.getSearchPreFetchThresholds().iterator(); iter.hasNext(); ) {
|
||||||
int next = iter.next();
|
int next = iter.next();
|
||||||
if (next != -1 && next <= currentlyLoaded) {
|
if (next != -1 && next <= currentlyLoaded) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -774,7 +783,7 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
||||||
/*
|
/*
|
||||||
* Construct the SQL query we'll be sending to the database
|
* Construct the SQL query we'll be sending to the database
|
||||||
*/
|
*/
|
||||||
Iterator<Long> theResultIterator = sb.createQuery(myParams, getSearch.getUuid());
|
IResultIterator theResultIterator = sb.createQuery(myParams, mySearch.getUuid());
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The following loop actually loads the PIDs of the resources
|
* The following loop actually loads the PIDs of the resources
|
||||||
|
@ -940,13 +949,33 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
||||||
|
|
||||||
int pageIndex = theFromIndex / pageSize;
|
int pageIndex = theFromIndex / pageSize;
|
||||||
|
|
||||||
Pageable page = new PageRequest(pageIndex, pageSize) {
|
Pageable page = new AbstractPageRequest(pageIndex, pageSize) {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getOffset() {
|
public long getOffset() {
|
||||||
return theFromIndex;
|
return theFromIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Sort getSort() {
|
||||||
|
return Sort.unsorted();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Pageable next() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Pageable previous() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Pageable first() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return page;
|
return page;
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
package ca.uhn.fhir.jpa.search.warm;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.ConfigurationException;
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||||
|
import ca.uhn.fhir.jpa.dao.*;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class CacheWarmingSvcImpl implements ICacheWarmingSvc {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private DaoConfig myDaoConfig;
|
||||||
|
private Map<WarmCacheEntry, Long> myCacheEntryToNextRefresh = new LinkedHashMap<>();
|
||||||
|
@Autowired
|
||||||
|
private FhirContext myCtx;
|
||||||
|
@Autowired
|
||||||
|
private DaoRegistry myDaoRegistry;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Scheduled(fixedDelay = 1000)
|
||||||
|
public synchronized void performWarmingPass() {
|
||||||
|
|
||||||
|
for (WarmCacheEntry nextCacheEntry : new ArrayList<>(myCacheEntryToNextRefresh.keySet())) {
|
||||||
|
|
||||||
|
long nextRefresh = myCacheEntryToNextRefresh.get(nextCacheEntry);
|
||||||
|
if (nextRefresh < System.currentTimeMillis()) {
|
||||||
|
|
||||||
|
// Perform the search
|
||||||
|
refreshNow(nextCacheEntry);
|
||||||
|
|
||||||
|
// Set the next time to warm this search
|
||||||
|
nextRefresh = nextCacheEntry.getPeriodMillis() + System.currentTimeMillis();
|
||||||
|
myCacheEntryToNextRefresh.put(nextCacheEntry, nextRefresh);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void refreshNow(WarmCacheEntry theCacheEntry) {
|
||||||
|
String nextUrl = theCacheEntry.getUrl();
|
||||||
|
|
||||||
|
RuntimeResourceDefinition resourceDef = parseWarmUrlResourceType(nextUrl);
|
||||||
|
IFhirResourceDao<?> callingDao = myDaoRegistry.getResourceDao(resourceDef.getName());
|
||||||
|
String queryPart = parseWarmUrlParamPart(nextUrl);
|
||||||
|
SearchParameterMap responseCriteriaUrl = BaseHapiFhirDao.translateMatchUrl(callingDao, myCtx, queryPart, resourceDef);
|
||||||
|
|
||||||
|
callingDao.search(responseCriteriaUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String parseWarmUrlParamPart(String theNextUrl) {
|
||||||
|
int paramIndex = theNextUrl.indexOf('?');
|
||||||
|
if (paramIndex == -1) {
|
||||||
|
throw new ConfigurationException("Invalid warm cache URL (must have ? character)");
|
||||||
|
}
|
||||||
|
return theNextUrl.substring(paramIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
private RuntimeResourceDefinition parseWarmUrlResourceType(String theNextUrl) {
|
||||||
|
int paramIndex = theNextUrl.indexOf('?');
|
||||||
|
String resourceName = theNextUrl.substring(0, paramIndex);
|
||||||
|
if (resourceName.contains("/")) {
|
||||||
|
resourceName = resourceName.substring(resourceName.lastIndexOf('/') + 1);
|
||||||
|
}
|
||||||
|
RuntimeResourceDefinition resourceDef = myCtx.getResourceDefinition(resourceName);
|
||||||
|
return resourceDef;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void start() {
|
||||||
|
initCacheMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void initCacheMap() {
|
||||||
|
|
||||||
|
myCacheEntryToNextRefresh.clear();
|
||||||
|
List<WarmCacheEntry> warmCacheEntries = myDaoConfig.getWarmCacheEntries();
|
||||||
|
for (WarmCacheEntry next : warmCacheEntries) {
|
||||||
|
|
||||||
|
// Validate
|
||||||
|
parseWarmUrlParamPart(next.getUrl());
|
||||||
|
parseWarmUrlResourceType(next.getUrl());
|
||||||
|
|
||||||
|
myCacheEntryToNextRefresh.put(next, 0L);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
package ca.uhn.fhir.jpa.search.warm;
|
||||||
|
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
|
||||||
|
public interface ICacheWarmingSvc {
|
||||||
|
@Scheduled(fixedDelay = 1000)
|
||||||
|
void performWarmingPass();
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
package ca.uhn.fhir.jpa.search.warm;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||||
|
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Denotes a search that should be performed in the background
|
||||||
|
* periodically in order to keep a fresh copy in the query cache.
|
||||||
|
* This improves performance for searches by keeping a copy
|
||||||
|
* loaded in the background.
|
||||||
|
*/
|
||||||
|
public class WarmCacheEntry {
|
||||||
|
|
||||||
|
private long myPeriodMillis;
|
||||||
|
private String myUrl;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object theO) {
|
||||||
|
if (this == theO) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (theO == null || getClass() != theO.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
WarmCacheEntry that = (WarmCacheEntry) theO;
|
||||||
|
|
||||||
|
return new EqualsBuilder()
|
||||||
|
.append(myPeriodMillis, that.myPeriodMillis)
|
||||||
|
.append(myUrl, that.myUrl)
|
||||||
|
.isEquals();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return new HashCodeBuilder(17, 37)
|
||||||
|
.append(myPeriodMillis)
|
||||||
|
.append(myUrl)
|
||||||
|
.toHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getPeriodMillis() {
|
||||||
|
return myPeriodMillis;
|
||||||
|
}
|
||||||
|
|
||||||
|
public WarmCacheEntry setPeriodMillis(long thePeriodMillis) {
|
||||||
|
myPeriodMillis = thePeriodMillis;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUrl() {
|
||||||
|
return myUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public WarmCacheEntry setUrl(String theUrl) {
|
||||||
|
myUrl = theUrl;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -7,7 +7,6 @@ import net.ttddyy.dsproxy.listener.ThreadQueryCountHolder;
|
||||||
import net.ttddyy.dsproxy.listener.logging.SLF4JLogLevel;
|
import net.ttddyy.dsproxy.listener.logging.SLF4JLogLevel;
|
||||||
import net.ttddyy.dsproxy.support.ProxyDataSourceBuilder;
|
import net.ttddyy.dsproxy.support.ProxyDataSourceBuilder;
|
||||||
import org.apache.commons.dbcp2.BasicDataSource;
|
import org.apache.commons.dbcp2.BasicDataSource;
|
||||||
import org.hibernate.query.criteria.LiteralHandlingMode;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
@ -23,7 +22,7 @@ import java.sql.SQLException;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableTransactionManagement()
|
@EnableTransactionManagement()
|
||||||
|
@ -134,7 +133,6 @@ public class TestR4Config extends BaseJavaConfigR4 {
|
||||||
extraProperties.put("hibernate.search.default.directory_provider", "ram");
|
extraProperties.put("hibernate.search.default.directory_provider", "ram");
|
||||||
extraProperties.put("hibernate.search.lucene_version", "LUCENE_CURRENT");
|
extraProperties.put("hibernate.search.lucene_version", "LUCENE_CURRENT");
|
||||||
extraProperties.put("hibernate.search.autoregister_listeners", "true");
|
extraProperties.put("hibernate.search.autoregister_listeners", "true");
|
||||||
extraProperties.put("hibernate.criteria.literal_handling_mode", LiteralHandlingMode.BIND);
|
|
||||||
|
|
||||||
return extraProperties;
|
return extraProperties;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import ca.uhn.fhir.jpa.provider.r4.JpaSystemProviderR4;
|
||||||
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
||||||
import ca.uhn.fhir.jpa.search.ISearchCoordinatorSvc;
|
import ca.uhn.fhir.jpa.search.ISearchCoordinatorSvc;
|
||||||
import ca.uhn.fhir.jpa.search.IStaleSearchDeletingSvc;
|
import ca.uhn.fhir.jpa.search.IStaleSearchDeletingSvc;
|
||||||
|
import ca.uhn.fhir.jpa.search.warm.ICacheWarmingSvc;
|
||||||
import ca.uhn.fhir.jpa.sp.ISearchParamPresenceSvc;
|
import ca.uhn.fhir.jpa.sp.ISearchParamPresenceSvc;
|
||||||
import ca.uhn.fhir.jpa.term.BaseHapiTerminologySvcImpl;
|
import ca.uhn.fhir.jpa.term.BaseHapiTerminologySvcImpl;
|
||||||
import ca.uhn.fhir.jpa.term.IHapiTerminologySvc;
|
import ca.uhn.fhir.jpa.term.IHapiTerminologySvc;
|
||||||
|
@ -51,7 +52,7 @@ import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.fail;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
@RunWith(SpringJUnit4ClassRunner.class)
|
@RunWith(SpringJUnit4ClassRunner.class)
|
||||||
|
@ -260,6 +261,8 @@ public abstract class BaseJpaR4Test extends BaseJpaTest {
|
||||||
@Autowired
|
@Autowired
|
||||||
protected ITermConceptMapGroupElementTargetDao myTermConceptMapGroupElementTargetDao;
|
protected ITermConceptMapGroupElementTargetDao myTermConceptMapGroupElementTargetDao;
|
||||||
@Autowired
|
@Autowired
|
||||||
|
protected ICacheWarmingSvc myCacheWarmingSvc;
|
||||||
|
@Autowired
|
||||||
private JpaValidationSupportChainR4 myJpaValidationSupportChainR4;
|
private JpaValidationSupportChainR4 myJpaValidationSupportChainR4;
|
||||||
|
|
||||||
@After()
|
@After()
|
||||||
|
|
|
@ -0,0 +1,112 @@
|
||||||
|
package ca.uhn.fhir.jpa.dao.r4;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.ConfigurationException;
|
||||||
|
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||||
|
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
|
||||||
|
import ca.uhn.fhir.jpa.search.PersistedJpaBundleProvider;
|
||||||
|
import ca.uhn.fhir.jpa.search.warm.CacheWarmingSvcImpl;
|
||||||
|
import ca.uhn.fhir.jpa.search.warm.WarmCacheEntry;
|
||||||
|
import ca.uhn.fhir.parser.DataFormatException;
|
||||||
|
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||||
|
import ca.uhn.fhir.rest.param.StringParam;
|
||||||
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
|
import org.hl7.fhir.r4.model.Patient;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
public class FhirResourceDaoR4CacheWarmingTest extends BaseJpaR4Test {
|
||||||
|
private static final Logger ourLog = LoggerFactory.getLogger(FhirResourceDaoR4CacheWarmingTest.class);
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void afterResetDao() {
|
||||||
|
myDaoConfig.setResourceServerIdStrategy(new DaoConfig().getResourceServerIdStrategy());
|
||||||
|
|
||||||
|
myDaoConfig.setWarmCacheEntries(new ArrayList<>());
|
||||||
|
CacheWarmingSvcImpl cacheWarmingSvc = (CacheWarmingSvcImpl) myCacheWarmingSvc;
|
||||||
|
cacheWarmingSvc.initCacheMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInvalidCacheEntries() {
|
||||||
|
CacheWarmingSvcImpl cacheWarmingSvc = (CacheWarmingSvcImpl) myCacheWarmingSvc;
|
||||||
|
|
||||||
|
myDaoConfig.setWarmCacheEntries(new ArrayList<>());
|
||||||
|
myDaoConfig.getWarmCacheEntries().add(
|
||||||
|
new WarmCacheEntry()
|
||||||
|
.setPeriodMillis(10)
|
||||||
|
.setUrl("BadResource?name=smith")
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
cacheWarmingSvc.initCacheMap();
|
||||||
|
fail();
|
||||||
|
} catch (DataFormatException e) {
|
||||||
|
assertEquals("Unknown resource name \"BadResource\" (this name is not known in FHIR version \"R4\")", e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
myDaoConfig.setWarmCacheEntries(new ArrayList<>());
|
||||||
|
myDaoConfig.getWarmCacheEntries().add(
|
||||||
|
new WarmCacheEntry()
|
||||||
|
.setPeriodMillis(10)
|
||||||
|
.setUrl("foo/Patient")
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
cacheWarmingSvc.initCacheMap();
|
||||||
|
fail();
|
||||||
|
} catch (ConfigurationException e) {
|
||||||
|
assertEquals("Invalid warm cache URL (must have ? character)", e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testKeepCacheWarm() throws InterruptedException {
|
||||||
|
myDaoConfig.setWarmCacheEntries(new ArrayList<>());
|
||||||
|
myDaoConfig.getWarmCacheEntries().add(
|
||||||
|
new WarmCacheEntry()
|
||||||
|
.setPeriodMillis(10)
|
||||||
|
.setUrl("Patient?name=smith")
|
||||||
|
);
|
||||||
|
CacheWarmingSvcImpl cacheWarmingSvc = (CacheWarmingSvcImpl) myCacheWarmingSvc;
|
||||||
|
cacheWarmingSvc.initCacheMap();
|
||||||
|
|
||||||
|
Patient p1 = new Patient();
|
||||||
|
p1.setId("p1");
|
||||||
|
p1.setActive(true);
|
||||||
|
myPatientDao.update(p1);
|
||||||
|
|
||||||
|
Patient p2 = new Patient();
|
||||||
|
p2.setId("p2");
|
||||||
|
p2.setActive(true);
|
||||||
|
p2.addName().setFamily("Smith");
|
||||||
|
myPatientDao.update(p2);
|
||||||
|
|
||||||
|
Thread.sleep(2000);
|
||||||
|
|
||||||
|
SearchParameterMap params = new SearchParameterMap();
|
||||||
|
params.add("name", new StringParam("smith"));
|
||||||
|
IBundleProvider result = myPatientDao.search(params);
|
||||||
|
assertEquals(PersistedJpaBundleProvider.class, result.getClass());
|
||||||
|
|
||||||
|
PersistedJpaBundleProvider resultCasted = (PersistedJpaBundleProvider) result;
|
||||||
|
assertTrue(resultCasted.isCacheHit());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void afterClassClearContext() {
|
||||||
|
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,8 +1,10 @@
|
||||||
package ca.uhn.fhir.jpa.dao.r4;
|
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.jpa.dao.SearchParameterMap;
|
||||||
import ca.uhn.fhir.jpa.entity.Search;
|
import ca.uhn.fhir.jpa.entity.Search;
|
||||||
import ca.uhn.fhir.jpa.entity.SearchStatusEnum;
|
import ca.uhn.fhir.jpa.entity.SearchStatusEnum;
|
||||||
|
import ca.uhn.fhir.jpa.search.SearchCoordinatorSvcImpl;
|
||||||
import ca.uhn.fhir.rest.api.SortSpec;
|
import ca.uhn.fhir.rest.api.SortSpec;
|
||||||
import ca.uhn.fhir.rest.api.SummaryEnum;
|
import ca.uhn.fhir.rest.api.SummaryEnum;
|
||||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||||
|
@ -15,6 +17,7 @@ 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.aop.framework.AopProxyUtils;
|
||||||
import org.springframework.scheduling.concurrent.ThreadPoolExecutorFactoryBean;
|
import org.springframework.scheduling.concurrent.ThreadPoolExecutorFactoryBean;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -26,17 +29,24 @@ import java.util.concurrent.Future;
|
||||||
import static org.apache.commons.lang3.StringUtils.leftPad;
|
import static org.apache.commons.lang3.StringUtils.leftPad;
|
||||||
import static org.hamcrest.Matchers.empty;
|
import static org.hamcrest.Matchers.empty;
|
||||||
import static org.hamcrest.Matchers.hasSize;
|
import static org.hamcrest.Matchers.hasSize;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.*;
|
||||||
import static org.junit.Assert.assertNull;
|
|
||||||
import static org.junit.Assert.assertThat;
|
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked", "deprecation", "Duplicates"})
|
@SuppressWarnings({"unchecked", "deprecation", "Duplicates"})
|
||||||
public class FhirResourceDaoR4SearchOptimizedTest extends BaseJpaR4Test {
|
public class FhirResourceDaoR4SearchOptimizedTest extends BaseJpaR4Test {
|
||||||
|
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoR4SearchOptimizedTest.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoR4SearchOptimizedTest.class);
|
||||||
|
private SearchCoordinatorSvcImpl mySearchCoordinatorSvcImpl;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void before() {
|
||||||
|
mySearchCoordinatorSvcImpl = (SearchCoordinatorSvcImpl) AopProxyUtils.getSingletonTarget(mySearchCoordinatorSvc);
|
||||||
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public final void after() {
|
public final void after() {
|
||||||
|
mySearchCoordinatorSvcImpl.setLoadingThrottleForUnitTests(null);
|
||||||
|
mySearchCoordinatorSvcImpl.setSyncSizeForUnitTests(SearchCoordinatorSvcImpl.DEFAULT_SYNC_SIZE);
|
||||||
|
myDaoConfig.setSearchPreFetchThresholds(new DaoConfig().getSearchPreFetchThresholds());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
|
@ -62,6 +72,7 @@ public class FhirResourceDaoR4SearchOptimizedTest extends BaseJpaR4Test {
|
||||||
params.setSummaryMode(Sets.newHashSet(SummaryEnum.COUNT));
|
params.setSummaryMode(Sets.newHashSet(SummaryEnum.COUNT));
|
||||||
IBundleProvider results = myPatientDao.search(params);
|
IBundleProvider results = myPatientDao.search(params);
|
||||||
String uuid = results.getUuid();
|
String uuid = results.getUuid();
|
||||||
|
ourLog.info("** Search returned UUID: {}", uuid);
|
||||||
assertEquals(200, results.size().intValue());
|
assertEquals(200, results.size().intValue());
|
||||||
List<String> ids = toUnqualifiedVersionlessIdValues(results, 0, 10, true);
|
List<String> ids = toUnqualifiedVersionlessIdValues(results, 0, 10, true);
|
||||||
assertThat(ids, empty());
|
assertThat(ids, empty());
|
||||||
|
@ -90,6 +101,7 @@ public class FhirResourceDaoR4SearchOptimizedTest extends BaseJpaR4Test {
|
||||||
params.setSummaryMode(Sets.newHashSet(SummaryEnum.COUNT));
|
params.setSummaryMode(Sets.newHashSet(SummaryEnum.COUNT));
|
||||||
IBundleProvider results = myPatientDao.search(params);
|
IBundleProvider results = myPatientDao.search(params);
|
||||||
String uuid = results.getUuid();
|
String uuid = results.getUuid();
|
||||||
|
ourLog.info("** Search returned UUID: {}", uuid);
|
||||||
assertEquals(201, results.size().intValue());
|
assertEquals(201, results.size().intValue());
|
||||||
List<String> ids = toUnqualifiedVersionlessIdValues(results, 0, 10, true);
|
List<String> ids = toUnqualifiedVersionlessIdValues(results, 0, 10, true);
|
||||||
assertThat(ids, empty());
|
assertThat(ids, empty());
|
||||||
|
@ -101,6 +113,7 @@ public class FhirResourceDaoR4SearchOptimizedTest extends BaseJpaR4Test {
|
||||||
params.setSummaryMode(Sets.newHashSet(SummaryEnum.COUNT, SummaryEnum.DATA));
|
params.setSummaryMode(Sets.newHashSet(SummaryEnum.COUNT, SummaryEnum.DATA));
|
||||||
results = myPatientDao.search(params);
|
results = myPatientDao.search(params);
|
||||||
uuid = results.getUuid();
|
uuid = results.getUuid();
|
||||||
|
ourLog.info("** Search returned UUID: {}", uuid);
|
||||||
assertEquals(201, results.size().intValue());
|
assertEquals(201, results.size().intValue());
|
||||||
ids = toUnqualifiedVersionlessIdValues(results, 0, 10, true);
|
ids = toUnqualifiedVersionlessIdValues(results, 0, 10, true);
|
||||||
assertThat(ids, hasSize(10));
|
assertThat(ids, hasSize(10));
|
||||||
|
@ -112,6 +125,7 @@ public class FhirResourceDaoR4SearchOptimizedTest extends BaseJpaR4Test {
|
||||||
params.setSummaryMode(Sets.newHashSet(SummaryEnum.COUNT));
|
params.setSummaryMode(Sets.newHashSet(SummaryEnum.COUNT));
|
||||||
results = myPatientDao.search(params);
|
results = myPatientDao.search(params);
|
||||||
uuid = results.getUuid();
|
uuid = results.getUuid();
|
||||||
|
ourLog.info("** Search returned UUID: {}", uuid);
|
||||||
assertEquals(201, results.size().intValue());
|
assertEquals(201, results.size().intValue());
|
||||||
ids = toUnqualifiedVersionlessIdValues(results, 0, 10, true);
|
ids = toUnqualifiedVersionlessIdValues(results, 0, 10, true);
|
||||||
assertThat(ids, empty());
|
assertThat(ids, empty());
|
||||||
|
@ -119,6 +133,33 @@ public class FhirResourceDaoR4SearchOptimizedTest extends BaseJpaR4Test {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFetchCountAndDataForSlowLoading() {
|
||||||
|
mySearchCoordinatorSvcImpl.setLoadingThrottleForUnitTests(25);
|
||||||
|
mySearchCoordinatorSvcImpl.setSyncSizeForUnitTests(10);
|
||||||
|
|
||||||
|
myDaoConfig.setSearchPreFetchThresholds(Arrays.asList(1000, -1));
|
||||||
|
|
||||||
|
SearchParameterMap params = new SearchParameterMap();
|
||||||
|
params.setSort(new SortSpec(Patient.SP_NAME));
|
||||||
|
params.setCount(5);
|
||||||
|
params.setSummaryMode(Sets.newHashSet(SummaryEnum.COUNT, SummaryEnum.DATA));
|
||||||
|
IBundleProvider results = myPatientDao.search(params);
|
||||||
|
String uuid = results.getUuid();
|
||||||
|
ourLog.info("** Search returned UUID: {}", uuid);
|
||||||
|
|
||||||
|
// assertEquals(200, myDatabaseBackedPagingProvider.retrieveResultList(uuid).size().intValue());
|
||||||
|
assertEquals(200, results.size().intValue());
|
||||||
|
ourLog.info("** Asking for results");
|
||||||
|
List<String> ids = toUnqualifiedVersionlessIdValues(results, 0, 5, true);
|
||||||
|
assertEquals("Patient/PT00000", ids.get(0));
|
||||||
|
assertEquals("Patient/PT00004", ids.get(4));
|
||||||
|
|
||||||
|
ourLog.info("** About to make new query for search with UUID: {}", uuid);
|
||||||
|
IBundleProvider search2 = myDatabaseBackedPagingProvider.retrieveResultList(uuid);
|
||||||
|
Integer search2Size = search2.size();
|
||||||
|
assertEquals(200, search2Size.intValue());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFetchCountAndData() {
|
public void testFetchCountAndData() {
|
||||||
|
@ -130,11 +171,28 @@ public class FhirResourceDaoR4SearchOptimizedTest extends BaseJpaR4Test {
|
||||||
params.setSummaryMode(Sets.newHashSet(SummaryEnum.COUNT, SummaryEnum.DATA));
|
params.setSummaryMode(Sets.newHashSet(SummaryEnum.COUNT, SummaryEnum.DATA));
|
||||||
IBundleProvider results = myPatientDao.search(params);
|
IBundleProvider results = myPatientDao.search(params);
|
||||||
String uuid = results.getUuid();
|
String uuid = results.getUuid();
|
||||||
|
ourLog.info("** Search returned UUID: {}", uuid);
|
||||||
assertEquals(200, results.size().intValue());
|
assertEquals(200, results.size().intValue());
|
||||||
List<String> ids = toUnqualifiedVersionlessIdValues(results, 0, 10, true);
|
List<String> ids = toUnqualifiedVersionlessIdValues(results, 0, 10, true);
|
||||||
assertEquals("Patient/PT00000", ids.get(0));
|
assertEquals("Patient/PT00000", ids.get(0));
|
||||||
assertEquals("Patient/PT00009", ids.get(9));
|
assertEquals("Patient/PT00009", ids.get(9));
|
||||||
assertEquals(200, myDatabaseBackedPagingProvider.retrieveResultList(uuid).size().intValue());
|
assertEquals(200, myDatabaseBackedPagingProvider.retrieveResultList(uuid).size().intValue());
|
||||||
|
|
||||||
|
// Try the same query again. This time the same thing should come back, but
|
||||||
|
// from the cache...
|
||||||
|
|
||||||
|
params = new SearchParameterMap();
|
||||||
|
params.setSort(new SortSpec(Patient.SP_NAME));
|
||||||
|
params.setSummaryMode(Sets.newHashSet(SummaryEnum.COUNT, SummaryEnum.DATA));
|
||||||
|
results = myPatientDao.search(params);
|
||||||
|
uuid = results.getUuid();
|
||||||
|
ourLog.info("** Search returned UUID: {}", uuid);
|
||||||
|
assertEquals(200, results.size().intValue());
|
||||||
|
ids = toUnqualifiedVersionlessIdValues(results, 0, 10, true);
|
||||||
|
assertEquals("Patient/PT00000", ids.get(0));
|
||||||
|
assertEquals("Patient/PT00009", ids.get(9));
|
||||||
|
assertEquals(200, myDatabaseBackedPagingProvider.retrieveResultList(uuid).size().intValue());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -150,6 +208,7 @@ public class FhirResourceDaoR4SearchOptimizedTest extends BaseJpaR4Test {
|
||||||
params.setSort(new SortSpec(Patient.SP_NAME));
|
params.setSort(new SortSpec(Patient.SP_NAME));
|
||||||
IBundleProvider results = myPatientDao.search(params);
|
IBundleProvider results = myPatientDao.search(params);
|
||||||
String uuid = results.getUuid();
|
String uuid = results.getUuid();
|
||||||
|
ourLog.info("** Search returned UUID: {}", uuid);
|
||||||
List<String> ids = toUnqualifiedVersionlessIdValues(results, 0, 200, true);
|
List<String> ids = toUnqualifiedVersionlessIdValues(results, 0, 200, true);
|
||||||
assertEquals("Patient/PT00000", ids.get(0));
|
assertEquals("Patient/PT00000", ids.get(0));
|
||||||
assertEquals("Patient/PT00199", ids.get(199));
|
assertEquals("Patient/PT00199", ids.get(199));
|
||||||
|
@ -203,6 +262,7 @@ public class FhirResourceDaoR4SearchOptimizedTest extends BaseJpaR4Test {
|
||||||
params.setSort(new SortSpec(Patient.SP_NAME));
|
params.setSort(new SortSpec(Patient.SP_NAME));
|
||||||
IBundleProvider results = myPatientDao.search(params);
|
IBundleProvider results = myPatientDao.search(params);
|
||||||
String uuid = results.getUuid();
|
String uuid = results.getUuid();
|
||||||
|
ourLog.info("** Search returned UUID: {}", uuid);
|
||||||
List<String> ids = toUnqualifiedVersionlessIdValues(results, 0, 10, true);
|
List<String> ids = toUnqualifiedVersionlessIdValues(results, 0, 10, true);
|
||||||
assertEquals("Patient/PT00000", ids.get(0));
|
assertEquals("Patient/PT00000", ids.get(0));
|
||||||
assertEquals("Patient/PT00009", ids.get(9));
|
assertEquals("Patient/PT00009", ids.get(9));
|
||||||
|
@ -328,6 +388,7 @@ public class FhirResourceDaoR4SearchOptimizedTest extends BaseJpaR4Test {
|
||||||
params.setCount(50);
|
params.setCount(50);
|
||||||
IBundleProvider results = myPatientDao.search(params);
|
IBundleProvider results = myPatientDao.search(params);
|
||||||
String uuid = results.getUuid();
|
String uuid = results.getUuid();
|
||||||
|
ourLog.info("** Search returned UUID: {}", uuid);
|
||||||
List<String> ids = toUnqualifiedVersionlessIdValues(results, 0, 50, true);
|
List<String> ids = toUnqualifiedVersionlessIdValues(results, 0, 50, true);
|
||||||
assertEquals("Patient/PT00000", ids.get(0));
|
assertEquals("Patient/PT00000", ids.get(0));
|
||||||
assertEquals("Patient/PT00049", ids.get(49));
|
assertEquals("Patient/PT00049", ids.get(49));
|
||||||
|
@ -361,6 +422,7 @@ public class FhirResourceDaoR4SearchOptimizedTest extends BaseJpaR4Test {
|
||||||
params.setSort(new SortSpec(Patient.SP_NAME));
|
params.setSort(new SortSpec(Patient.SP_NAME));
|
||||||
IBundleProvider results = myPatientDao.search(params);
|
IBundleProvider results = myPatientDao.search(params);
|
||||||
String uuid = results.getUuid();
|
String uuid = results.getUuid();
|
||||||
|
ourLog.info("** Search returned UUID: {}", uuid);
|
||||||
List<String> ids = toUnqualifiedVersionlessIdValues(results, 0, 10, true);
|
List<String> ids = toUnqualifiedVersionlessIdValues(results, 0, 10, true);
|
||||||
assertEquals("Patient/PT00000", ids.get(0));
|
assertEquals("Patient/PT00000", ids.get(0));
|
||||||
assertEquals("Patient/PT00009", ids.get(9));
|
assertEquals("Patient/PT00009", ids.get(9));
|
||||||
|
@ -418,6 +480,7 @@ public class FhirResourceDaoR4SearchOptimizedTest extends BaseJpaR4Test {
|
||||||
params.setSort(new SortSpec(Patient.SP_NAME));
|
params.setSort(new SortSpec(Patient.SP_NAME));
|
||||||
final IBundleProvider results = myPatientDao.search(params);
|
final IBundleProvider results = myPatientDao.search(params);
|
||||||
String uuid = results.getUuid();
|
String uuid = results.getUuid();
|
||||||
|
ourLog.info("** Search returned UUID: {}", uuid);
|
||||||
List<String> ids = toUnqualifiedVersionlessIdValues(results, 0, 10, true);
|
List<String> ids = toUnqualifiedVersionlessIdValues(results, 0, 10, true);
|
||||||
assertEquals("Patient/PT00000", ids.get(0));
|
assertEquals("Patient/PT00000", ids.get(0));
|
||||||
assertEquals("Patient/PT00009", ids.get(9));
|
assertEquals("Patient/PT00009", ids.get(9));
|
||||||
|
@ -482,6 +545,7 @@ public class FhirResourceDaoR4SearchOptimizedTest extends BaseJpaR4Test {
|
||||||
params.add(Patient.SP_RES_ID, new TokenParam("PT00000"));
|
params.add(Patient.SP_RES_ID, new TokenParam("PT00000"));
|
||||||
IBundleProvider results = myPatientDao.search(params);
|
IBundleProvider results = myPatientDao.search(params);
|
||||||
String uuid = results.getUuid();
|
String uuid = results.getUuid();
|
||||||
|
ourLog.info("** Search returned UUID: {}", uuid);
|
||||||
List<String> ids = toUnqualifiedVersionlessIdValues(results, 0, 10, true);
|
List<String> ids = toUnqualifiedVersionlessIdValues(results, 0, 10, true);
|
||||||
assertEquals("Patient/PT00000", ids.get(0));
|
assertEquals("Patient/PT00000", ids.get(0));
|
||||||
assertEquals(1, ids.size());
|
assertEquals(1, ids.size());
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package ca.uhn.fhir.jpa.dao.r4;
|
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.jpa.dao.SearchParameterMap;
|
||||||
import ca.uhn.fhir.rest.api.Constants;
|
import ca.uhn.fhir.rest.api.Constants;
|
||||||
import ca.uhn.fhir.rest.api.SortOrderEnum;
|
import ca.uhn.fhir.rest.api.SortOrderEnum;
|
||||||
|
@ -206,31 +207,38 @@ public class FhirResourceDaoR4SortTest extends BaseJpaR4Test {
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
@Test
|
@Test
|
||||||
public void testSortOnSparselyPopulatedFields() {
|
public void testSortOnSparselyPopulatedFields() {
|
||||||
|
// myDaoConfig.setIndexMissingFields(DaoConfig.IndexEnabledEnum.DISABLED);
|
||||||
|
|
||||||
IIdType pid1, pid2, pid3, pid4, pid5, pid6;
|
IIdType pid1, pid2, pid3, pid4, pid5, pid6;
|
||||||
{
|
{
|
||||||
Patient p = new Patient();
|
Patient p = new Patient();
|
||||||
|
p.setId("pid1");
|
||||||
p.setActive(true);
|
p.setActive(true);
|
||||||
pid1 = myPatientDao.create(p, mySrd).getId().toUnqualifiedVersionless();
|
pid1 = myPatientDao.update(p, mySrd).getId().toUnqualifiedVersionless();
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
Patient p = new Patient();
|
Patient p = new Patient();
|
||||||
|
p.setId("pid2");
|
||||||
p.addName().setFamily("A");
|
p.addName().setFamily("A");
|
||||||
pid2 = myPatientDao.create(p, mySrd).getId().toUnqualifiedVersionless();
|
pid2 = myPatientDao.update(p, mySrd).getId().toUnqualifiedVersionless();
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
Patient p = new Patient();
|
Patient p = new Patient();
|
||||||
|
p.setId("pid3");
|
||||||
p.addName().setFamily("B");
|
p.addName().setFamily("B");
|
||||||
pid3 = myPatientDao.create(p, mySrd).getId().toUnqualifiedVersionless();
|
pid3 = myPatientDao.update(p, mySrd).getId().toUnqualifiedVersionless();
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
Patient p = new Patient();
|
Patient p = new Patient();
|
||||||
|
p.setId("pid4");
|
||||||
p.addName().setFamily("B").addGiven("A");
|
p.addName().setFamily("B").addGiven("A");
|
||||||
pid4 = myPatientDao.create(p, mySrd).getId().toUnqualifiedVersionless();
|
pid4 = myPatientDao.update(p, mySrd).getId().toUnqualifiedVersionless();
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
Patient p = new Patient();
|
Patient p = new Patient();
|
||||||
|
p.setId("pid5");
|
||||||
p.addName().setFamily("B").addGiven("B");
|
p.addName().setFamily("B").addGiven("B");
|
||||||
pid5 = myPatientDao.create(p, mySrd).getId().toUnqualifiedVersionless();
|
pid5 = myPatientDao.update(p, mySrd).getId().toUnqualifiedVersionless();
|
||||||
}
|
}
|
||||||
|
|
||||||
SearchParameterMap map;
|
SearchParameterMap map;
|
||||||
|
@ -239,6 +247,7 @@ public class FhirResourceDaoR4SortTest extends BaseJpaR4Test {
|
||||||
map = new SearchParameterMap();
|
map = new SearchParameterMap();
|
||||||
map.setSort(new SortSpec(Patient.SP_FAMILY, SortOrderEnum.ASC).setChain(new SortSpec(Patient.SP_GIVEN, SortOrderEnum.ASC)));
|
map.setSort(new SortSpec(Patient.SP_FAMILY, SortOrderEnum.ASC).setChain(new SortSpec(Patient.SP_GIVEN, SortOrderEnum.ASC)));
|
||||||
ids = toUnqualifiedVersionlessIds(myPatientDao.search(map));
|
ids = toUnqualifiedVersionlessIds(myPatientDao.search(map));
|
||||||
|
ourLog.info("** Got IDs: {}", ids);
|
||||||
assertThat(ids, contains(pid2, pid4, pid5, pid3, pid1));
|
assertThat(ids, contains(pid2, pid4, pid5, pid3, pid1));
|
||||||
assertEquals(5, ids.size());
|
assertEquals(5, ids.size());
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,7 @@ public class PatientEverythingR4Test extends BaseResourceProviderR4Test {
|
||||||
|
|
||||||
myDaoConfig.setReuseCachedSearchResultsForMillis(new DaoConfig().getReuseCachedSearchResultsForMillis());
|
myDaoConfig.setReuseCachedSearchResultsForMillis(new DaoConfig().getReuseCachedSearchResultsForMillis());
|
||||||
myDaoConfig.setEverythingIncludesFetchPageSize(new DaoConfig().getEverythingIncludesFetchPageSize());
|
myDaoConfig.setEverythingIncludesFetchPageSize(new DaoConfig().getEverythingIncludesFetchPageSize());
|
||||||
|
myDaoConfig.setSearchPreFetchThresholds(new DaoConfig().getSearchPreFetchThresholds());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -58,10 +58,7 @@ import org.apache.http.entity.ContentType;
|
||||||
import org.apache.http.entity.StringEntity;
|
import org.apache.http.entity.StringEntity;
|
||||||
import org.apache.http.message.BasicNameValuePair;
|
import org.apache.http.message.BasicNameValuePair;
|
||||||
import org.hamcrest.Matchers;
|
import org.hamcrest.Matchers;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseBundle;
|
import org.hl7.fhir.instance.model.api.*;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
|
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
|
||||||
import org.hl7.fhir.r4.hapi.validation.FhirInstanceValidator;
|
import org.hl7.fhir.r4.hapi.validation.FhirInstanceValidator;
|
||||||
import org.hl7.fhir.r4.model.*;
|
import org.hl7.fhir.r4.model.*;
|
||||||
import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent;
|
import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent;
|
||||||
|
@ -142,6 +139,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
myDaoConfig.setAllowExternalReferences(new DaoConfig().isAllowExternalReferences());
|
myDaoConfig.setAllowExternalReferences(new DaoConfig().isAllowExternalReferences());
|
||||||
myDaoConfig.setReuseCachedSearchResultsForMillis(new DaoConfig().getReuseCachedSearchResultsForMillis());
|
myDaoConfig.setReuseCachedSearchResultsForMillis(new DaoConfig().getReuseCachedSearchResultsForMillis());
|
||||||
myDaoConfig.setCountSearchResultsUpTo(new DaoConfig().getCountSearchResultsUpTo());
|
myDaoConfig.setCountSearchResultsUpTo(new DaoConfig().getCountSearchResultsUpTo());
|
||||||
|
myDaoConfig.setSearchPreFetchThresholds(new DaoConfig().getSearchPreFetchThresholds());
|
||||||
|
|
||||||
mySearchCoordinatorSvcRaw.setLoadingThrottleForUnitTests(null);
|
mySearchCoordinatorSvcRaw.setLoadingThrottleForUnitTests(null);
|
||||||
mySearchCoordinatorSvcRaw.setSyncSizeForUnitTests(SearchCoordinatorSvcImpl.DEFAULT_SYNC_SIZE);
|
mySearchCoordinatorSvcRaw.setSyncSizeForUnitTests(SearchCoordinatorSvcImpl.DEFAULT_SYNC_SIZE);
|
||||||
|
@ -158,6 +156,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
|
|
||||||
myDaoConfig.setAllowMultipleDelete(true);
|
myDaoConfig.setAllowMultipleDelete(true);
|
||||||
ourClient.registerInterceptor(myCapturingInterceptor);
|
ourClient.registerInterceptor(myCapturingInterceptor);
|
||||||
|
myDaoConfig.setSearchPreFetchThresholds(new DaoConfig().getSearchPreFetchThresholds());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -469,7 +468,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
theRequest.addHeader(Constants.HEADER_PREFER, Constants.HEADER_PREFER_RETURN + "=" + Constants.HEADER_PREFER_RETURN_OPERATION_OUTCOME);
|
theRequest.addHeader(Constants.HEADER_PREFER, Constants.HEADER_PREFER_RETURN + "=" + Constants.HEADER_PREFER_RETURN_OPERATION_OUTCOME);
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void interceptResponse(IHttpResponse theResponse) throws IOException { // TODO Auto-generated method stu
|
public void interceptResponse(IHttpResponse theResponse) { // TODO Auto-generated method stu
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -968,9 +967,9 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
sock.setSoTimeout(3000);
|
sock.setSoTimeout(3000);
|
||||||
try {
|
try {
|
||||||
sock.connect(new InetSocketAddress("localhost", ourPort));
|
sock.connect(new InetSocketAddress("localhost", ourPort));
|
||||||
sock.getOutputStream().write(("DELETE /fhir/context/Patient?identifier=http://ghh.org/patient|" + methodName + " HTTP/1.1\n").getBytes("UTF-8"));
|
sock.getOutputStream().write(("DELETE /fhir/context/Patient?identifier=http://ghh.org/patient|" + methodName + " HTTP/1.1\n").getBytes(StandardCharsets.UTF_8));
|
||||||
sock.getOutputStream().write("Host: localhost\n".getBytes("UTF-8"));
|
sock.getOutputStream().write("Host: localhost\n".getBytes(StandardCharsets.UTF_8));
|
||||||
sock.getOutputStream().write("\n".getBytes("UTF-8"));
|
sock.getOutputStream().write("\n".getBytes(StandardCharsets.UTF_8));
|
||||||
|
|
||||||
BufferedReader socketInput = new BufferedReader(new InputStreamReader(sock.getInputStream()));
|
BufferedReader socketInput = new BufferedReader(new InputStreamReader(sock.getInputStream()));
|
||||||
|
|
||||||
|
@ -1637,6 +1636,8 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testEverythingWithLargeSet2() {
|
public void testEverythingWithLargeSet2() {
|
||||||
|
myDaoConfig.setSearchPreFetchThresholds(Arrays.asList(15, 30, -1));
|
||||||
|
|
||||||
Patient p = new Patient();
|
Patient p = new Patient();
|
||||||
p.setActive(true);
|
p.setActive(true);
|
||||||
IIdType id = ourClient.create().resource(p).execute().getId().toUnqualifiedVersionless();
|
IIdType id = ourClient.create().resource(p).execute().getId().toUnqualifiedVersionless();
|
||||||
|
@ -1648,7 +1649,13 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
ourClient.update().resource(obs).execute();
|
ourClient.update().resource(obs).execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
Bundle responseBundle = ourClient.operation().onInstance(id).named("everything").withParameter(Parameters.class, "_count", new IntegerType(50)).useHttpGet().returnResourceType(Bundle.class)
|
Bundle responseBundle = ourClient
|
||||||
|
.operation()
|
||||||
|
.onInstance(id)
|
||||||
|
.named("everything")
|
||||||
|
.withParameter(Parameters.class, "_count", new IntegerType(50))
|
||||||
|
.useHttpGet()
|
||||||
|
.returnResourceType(Bundle.class)
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
TreeSet<String> ids = new TreeSet<>();
|
TreeSet<String> ids = new TreeSet<>();
|
||||||
|
@ -1658,9 +1665,9 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ourLog.info("Have {} IDs: {}", ids.size(), ids);
|
|
||||||
|
|
||||||
BundleLinkComponent nextLink = responseBundle.getLink("next");
|
BundleLinkComponent nextLink = responseBundle.getLink("next");
|
||||||
|
ourLog.info("Have {} IDs with next link: ", ids.size(), nextLink);
|
||||||
|
|
||||||
while (nextLink != null) {
|
while (nextLink != null) {
|
||||||
String nextUrl = nextLink.getUrl();
|
String nextUrl = nextLink.getUrl();
|
||||||
responseBundle = ourClient.fetchResourceFromUrl(Bundle.class, nextUrl);
|
responseBundle = ourClient.fetchResourceFromUrl(Bundle.class, nextUrl);
|
||||||
|
@ -1670,8 +1677,8 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ourLog.info("Have {} IDs: {}", ids.size(), ids);
|
|
||||||
nextLink = responseBundle.getLink("next");
|
nextLink = responseBundle.getLink("next");
|
||||||
|
ourLog.info("Have {} IDs with next link: ", ids.size(), nextLink);
|
||||||
}
|
}
|
||||||
|
|
||||||
assertThat(ids, hasItem(id.getIdPart()));
|
assertThat(ids, hasItem(id.getIdPart()));
|
||||||
|
@ -2731,14 +2738,11 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
@Test
|
@Test
|
||||||
public void testSearchBundleDoesntIncludeTextElement() throws Exception {
|
public void testSearchBundleDoesntIncludeTextElement() throws Exception {
|
||||||
HttpGet read = new HttpGet(ourServerBase + "/Patient?_format=json");
|
HttpGet read = new HttpGet(ourServerBase + "/Patient?_format=json");
|
||||||
CloseableHttpResponse response = ourHttpClient.execute(read);
|
try (CloseableHttpResponse response = ourHttpClient.execute(read)) {
|
||||||
try {
|
|
||||||
String text = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
String text = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||||
ourLog.info(text);
|
ourLog.info(text);
|
||||||
assertEquals(Constants.STATUS_HTTP_200_OK, response.getStatusLine().getStatusCode());
|
assertEquals(Constants.STATUS_HTTP_200_OK, response.getStatusLine().getStatusCode());
|
||||||
assertThat(text, not(containsString("\"text\",\"type\"")));
|
assertThat(text, not(containsString("\"text\",\"type\"")));
|
||||||
} finally {
|
|
||||||
response.close();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2768,7 +2772,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
assertEquals("Jernelöv", p.getName().get(0).getFamily());
|
assertEquals("Jernelöv", p.getName().get(0).getFamily());
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
IOUtils.closeQuietly(resp.getEntity().getContent());
|
resp.getEntity().getContent().close();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2793,7 +2797,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
found = ourClient
|
found = ourClient
|
||||||
.search()
|
.search()
|
||||||
.forResource(Patient.class)
|
.forResource(Patient.class)
|
||||||
.where(BaseResource.RES_ID.exactly().systemAndValues(null, id1.getIdPart(), id2.getIdPart()))
|
.where(IAnyResource.RES_ID.exactly().systemAndValues(null, id1.getIdPart(), id2.getIdPart()))
|
||||||
.returnBundle(Bundle.class)
|
.returnBundle(Bundle.class)
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
|
@ -2802,7 +2806,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
found = ourClient
|
found = ourClient
|
||||||
.search()
|
.search()
|
||||||
.forResource(Patient.class)
|
.forResource(Patient.class)
|
||||||
.where(BaseResource.RES_ID.exactly().systemAndValues(null, Arrays.asList(id1.getIdPart(), id2.getIdPart(), "FOOOOO")))
|
.where(IAnyResource.RES_ID.exactly().systemAndValues(null, Arrays.asList(id1.getIdPart(), id2.getIdPart(), "FOOOOO")))
|
||||||
.returnBundle(Bundle.class)
|
.returnBundle(Bundle.class)
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
|
@ -2811,7 +2815,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
found = ourClient
|
found = ourClient
|
||||||
.search()
|
.search()
|
||||||
.forResource(Patient.class)
|
.forResource(Patient.class)
|
||||||
.where(BaseResource.RES_ID.exactly().systemAndCode(null, id1.getIdPart()))
|
.where(IAnyResource.RES_ID.exactly().systemAndCode(null, id1.getIdPart()))
|
||||||
.returnBundle(Bundle.class)
|
.returnBundle(Bundle.class)
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
|
@ -2820,8 +2824,8 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
found = ourClient
|
found = ourClient
|
||||||
.search()
|
.search()
|
||||||
.forResource(Patient.class)
|
.forResource(Patient.class)
|
||||||
.where(BaseResource.RES_ID.exactly().codes(id1.getIdPart(), id2.getIdPart()))
|
.where(IAnyResource.RES_ID.exactly().codes(id1.getIdPart(), id2.getIdPart()))
|
||||||
.and(BaseResource.RES_ID.exactly().code(id1.getIdPart()))
|
.and(IAnyResource.RES_ID.exactly().code(id1.getIdPart()))
|
||||||
.returnBundle(Bundle.class)
|
.returnBundle(Bundle.class)
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
|
@ -2830,8 +2834,8 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
found = ourClient
|
found = ourClient
|
||||||
.search()
|
.search()
|
||||||
.forResource(Patient.class)
|
.forResource(Patient.class)
|
||||||
.where(BaseResource.RES_ID.exactly().codes(Arrays.asList(id1.getIdPart(), id2.getIdPart(), "FOOOOO")))
|
.where(IAnyResource.RES_ID.exactly().codes(Arrays.asList(id1.getIdPart(), id2.getIdPart(), "FOOOOO")))
|
||||||
.and(BaseResource.RES_ID.exactly().code(id1.getIdPart()))
|
.and(IAnyResource.RES_ID.exactly().code(id1.getIdPart()))
|
||||||
.returnBundle(Bundle.class)
|
.returnBundle(Bundle.class)
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
|
@ -2840,7 +2844,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
found = ourClient
|
found = ourClient
|
||||||
.search()
|
.search()
|
||||||
.forResource(Patient.class)
|
.forResource(Patient.class)
|
||||||
.where(BaseResource.RES_ID.exactly().codes(id1.getIdPart(), id2.getIdPart(), "FOOO"))
|
.where(IAnyResource.RES_ID.exactly().codes(id1.getIdPart(), id2.getIdPart(), "FOOO"))
|
||||||
.returnBundle(Bundle.class)
|
.returnBundle(Bundle.class)
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
|
@ -2849,7 +2853,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
found = ourClient
|
found = ourClient
|
||||||
.search()
|
.search()
|
||||||
.forResource(Patient.class)
|
.forResource(Patient.class)
|
||||||
.where(BaseResource.RES_ID.exactly().codes("FOOO"))
|
.where(IAnyResource.RES_ID.exactly().codes("FOOO"))
|
||||||
.returnBundle(Bundle.class)
|
.returnBundle(Bundle.class)
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
|
@ -2867,7 +2871,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
Patient p2 = new Patient();
|
Patient p2 = new Patient();
|
||||||
p2.addIdentifier().setSystem("urn:system").setValue("testSearchByIdentifier02");
|
p2.addIdentifier().setSystem("urn:system").setValue("testSearchByIdentifier02");
|
||||||
p2.addName().setFamily("testSearchByIdentifierFamily01").addGiven("testSearchByIdentifierGiven02");
|
p2.addName().setFamily("testSearchByIdentifierFamily01").addGiven("testSearchByIdentifierGiven02");
|
||||||
ourClient.create().resource(p2).execute().getId();
|
ourClient.create().resource(p2).execute();
|
||||||
|
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
Bundle actual = ourClient
|
Bundle actual = ourClient
|
||||||
|
@ -2929,7 +2933,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
try {
|
try {
|
||||||
assertEquals(200, response.getStatusLine().getStatusCode());
|
assertEquals(200, response.getStatusLine().getStatusCode());
|
||||||
String output = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
String output = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||||
IOUtils.closeQuietly(response.getEntity().getContent());
|
response.getEntity().getContent().close();
|
||||||
ourLog.info(output);
|
ourLog.info(output);
|
||||||
List<IIdType> ids = toUnqualifiedVersionlessIds(myFhirCtx.newXmlParser().parseResource(Bundle.class, output));
|
List<IIdType> ids = toUnqualifiedVersionlessIds(myFhirCtx.newXmlParser().parseResource(Bundle.class, output));
|
||||||
ourLog.info(ids.toString());
|
ourLog.info(ids.toString());
|
||||||
|
@ -2943,7 +2947,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
try {
|
try {
|
||||||
assertEquals(200, response.getStatusLine().getStatusCode());
|
assertEquals(200, response.getStatusLine().getStatusCode());
|
||||||
String output = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
String output = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||||
IOUtils.closeQuietly(response.getEntity().getContent());
|
response.getEntity().getContent().close();
|
||||||
ourLog.info(output);
|
ourLog.info(output);
|
||||||
List<IIdType> ids = toUnqualifiedVersionlessIds(myFhirCtx.newXmlParser().parseResource(Bundle.class, output));
|
List<IIdType> ids = toUnqualifiedVersionlessIds(myFhirCtx.newXmlParser().parseResource(Bundle.class, output));
|
||||||
ourLog.info(ids.toString());
|
ourLog.info(ids.toString());
|
||||||
|
@ -2982,7 +2986,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
try {
|
try {
|
||||||
assertEquals(200, response.getStatusLine().getStatusCode());
|
assertEquals(200, response.getStatusLine().getStatusCode());
|
||||||
String output = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
String output = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||||
IOUtils.closeQuietly(response.getEntity().getContent());
|
response.getEntity().getContent().close();
|
||||||
ourLog.info(output);
|
ourLog.info(output);
|
||||||
List<String> ids = toUnqualifiedVersionlessIdValues(myFhirCtx.newXmlParser().parseResource(Bundle.class, output));
|
List<String> ids = toUnqualifiedVersionlessIdValues(myFhirCtx.newXmlParser().parseResource(Bundle.class, output));
|
||||||
ourLog.info(ids.toString());
|
ourLog.info(ids.toString());
|
||||||
|
@ -2996,7 +3000,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
try {
|
try {
|
||||||
assertEquals(200, response.getStatusLine().getStatusCode());
|
assertEquals(200, response.getStatusLine().getStatusCode());
|
||||||
String output = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
String output = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||||
IOUtils.closeQuietly(response.getEntity().getContent());
|
response.getEntity().getContent().close();
|
||||||
ourLog.info(output);
|
ourLog.info(output);
|
||||||
List<String> ids = toUnqualifiedVersionlessIdValues(myFhirCtx.newXmlParser().parseResource(Bundle.class, output));
|
List<String> ids = toUnqualifiedVersionlessIdValues(myFhirCtx.newXmlParser().parseResource(Bundle.class, output));
|
||||||
ourLog.info(ids.toString());
|
ourLog.info(ids.toString());
|
||||||
|
@ -3034,10 +3038,10 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
.where(Patient.ORGANIZATION.hasAnyOfIds(Arrays.asList(o1id.getIdPart(), o2id.getIdPart())))
|
.where(Patient.ORGANIZATION.hasAnyOfIds(Arrays.asList(o1id.getIdPart(), o2id.getIdPart())))
|
||||||
.encodedJson().prettyPrint().returnBundle(Bundle.class).execute();
|
.encodedJson().prettyPrint().returnBundle(Bundle.class).execute();
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
Set<String> expectedIds = new HashSet<String>();
|
Set<String> expectedIds = new HashSet<>();
|
||||||
expectedIds.add(p1Id.getIdPart());
|
expectedIds.add(p1Id.getIdPart());
|
||||||
expectedIds.add(p2Id.getIdPart());
|
expectedIds.add(p2Id.getIdPart());
|
||||||
Set<String> actualIds = new HashSet<String>();
|
Set<String> actualIds = new HashSet<>();
|
||||||
for (BundleEntryComponent ele : actual.getEntry()) {
|
for (BundleEntryComponent ele : actual.getEntry()) {
|
||||||
actualIds.add(ele.getResource().getIdElement().getIdPart());
|
actualIds.add(ele.getResource().getIdElement().getIdPart());
|
||||||
}
|
}
|
||||||
|
@ -3094,7 +3098,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
assertThat(respString, containsString("Invalid parameter chain: subject.id"));
|
assertThat(respString, containsString("Invalid parameter chain: subject.id"));
|
||||||
assertEquals(400, resp.getStatusLine().getStatusCode());
|
assertEquals(400, resp.getStatusLine().getStatusCode());
|
||||||
} finally {
|
} finally {
|
||||||
IOUtils.closeQuietly(resp.getEntity().getContent());
|
resp.getEntity().getContent().close();
|
||||||
}
|
}
|
||||||
ourLog.info("Outgoing post: {}", httpPost);
|
ourLog.info("Outgoing post: {}", httpPost);
|
||||||
}
|
}
|
||||||
|
@ -3212,14 +3216,11 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
IIdType moId = myMedicationAdministrationDao.create(ma).getId().toUnqualifiedVersionless();
|
IIdType moId = myMedicationAdministrationDao.create(ma).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
HttpGet get = new HttpGet(ourServerBase + "/MedicationAdministration?medication.code=04823543");
|
HttpGet get = new HttpGet(ourServerBase + "/MedicationAdministration?medication.code=04823543");
|
||||||
CloseableHttpResponse response = ourHttpClient.execute(get);
|
try (CloseableHttpResponse response = ourHttpClient.execute(get)) {
|
||||||
try {
|
|
||||||
assertEquals(200, response.getStatusLine().getStatusCode());
|
assertEquals(200, response.getStatusLine().getStatusCode());
|
||||||
String responseString = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
String responseString = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||||
ourLog.info(responseString);
|
ourLog.info(responseString);
|
||||||
assertThat(responseString, containsString(moId.getIdPart()));
|
assertThat(responseString, containsString(moId.getIdPart()));
|
||||||
} finally {
|
|
||||||
response.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3244,7 +3245,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
assertThat(ids, contains(oid1));
|
assertThat(ids, contains(oid1));
|
||||||
assertThat(ids, not(contains(oid2)));
|
assertThat(ids, not(contains(oid2)));
|
||||||
} finally {
|
} finally {
|
||||||
IOUtils.closeQuietly(resp);
|
resp.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3258,7 +3259,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
Patient patient = new Patient();
|
Patient patient = new Patient();
|
||||||
patient.addIdentifier().setSystem("urn:system").setValue("0");
|
patient.addIdentifier().setSystem("urn:system").setValue("0");
|
||||||
patient.addName().setFamily(methodName).addGiven("Joe");
|
patient.addName().setFamily(methodName).addGiven("Joe");
|
||||||
pid1 = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 1; i <= 20; i++) {
|
for (int i = 1; i <= 20; i++) {
|
||||||
|
@ -3289,7 +3290,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
HttpGet get = new HttpGet(ourServerBase + search);
|
HttpGet get = new HttpGet(ourServerBase + search);
|
||||||
CloseableHttpResponse response = ourHttpClient.execute(get);
|
CloseableHttpResponse response = ourHttpClient.execute(get);
|
||||||
String resp = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
String resp = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||||
IOUtils.closeQuietly(response.getEntity().getContent());
|
response.getEntity().getContent().close();
|
||||||
ourLog.info(resp);
|
ourLog.info(resp);
|
||||||
Bundle bundle = myFhirCtx.newXmlParser().parseResource(Bundle.class, resp);
|
Bundle bundle = myFhirCtx.newXmlParser().parseResource(Bundle.class, resp);
|
||||||
matches = bundle.getTotal();
|
matches = bundle.getTotal();
|
||||||
|
@ -3326,7 +3327,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSearchReusesNoParams() {
|
public void testSearchReusesNoParams() {
|
||||||
List<IBaseResource> resources = new ArrayList<IBaseResource>();
|
List<IBaseResource> resources = new ArrayList<>();
|
||||||
for (int i = 0; i < 50; i++) {
|
for (int i = 0; i < 50; i++) {
|
||||||
Organization org = new Organization();
|
Organization org = new Organization();
|
||||||
org.setName("HELLO");
|
org.setName("HELLO");
|
||||||
|
@ -3357,7 +3358,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSearchReusesResultsDisabled() {
|
public void testSearchReusesResultsDisabled() {
|
||||||
List<IBaseResource> resources = new ArrayList<IBaseResource>();
|
List<IBaseResource> resources = new ArrayList<>();
|
||||||
for (int i = 0; i < 50; i++) {
|
for (int i = 0; i < 50; i++) {
|
||||||
Organization org = new Organization();
|
Organization org = new Organization();
|
||||||
org.setName("HELLO");
|
org.setName("HELLO");
|
||||||
|
@ -3403,7 +3404,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSearchReusesResultsEnabled() throws Exception {
|
public void testSearchReusesResultsEnabled() throws Exception {
|
||||||
List<IBaseResource> resources = new ArrayList<IBaseResource>();
|
List<IBaseResource> resources = new ArrayList<>();
|
||||||
for (int i = 0; i < 50; i++) {
|
for (int i = 0; i < 50; i++) {
|
||||||
Organization org = new Organization();
|
Organization org = new Organization();
|
||||||
org.setName("HELLO");
|
org.setName("HELLO");
|
||||||
|
@ -3422,12 +3423,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
final String uuid1 = toSearchUuidFromLinkNext(result1);
|
final String uuid1 = toSearchUuidFromLinkNext(result1);
|
||||||
Search search1 = newTxTemplate().execute(new TransactionCallback<Search>() {
|
Search search1 = newTxTemplate().execute(theStatus -> mySearchEntityDao.findByUuid(uuid1));
|
||||||
@Override
|
|
||||||
public Search doInTransaction(TransactionStatus theStatus) {
|
|
||||||
return mySearchEntityDao.findByUuid(uuid1);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Date lastReturned1 = search1.getSearchLastReturned();
|
Date lastReturned1 = search1.getSearchLastReturned();
|
||||||
|
|
||||||
Bundle result2 = ourClient
|
Bundle result2 = ourClient
|
||||||
|
@ -3439,12 +3435,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
final String uuid2 = toSearchUuidFromLinkNext(result2);
|
final String uuid2 = toSearchUuidFromLinkNext(result2);
|
||||||
Search search2 = newTxTemplate().execute(new TransactionCallback<Search>() {
|
Search search2 = newTxTemplate().execute(theStatus -> mySearchEntityDao.findByUuid(uuid2));
|
||||||
@Override
|
|
||||||
public Search doInTransaction(TransactionStatus theStatus) {
|
|
||||||
return mySearchEntityDao.findByUuid(uuid2);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Date lastReturned2 = search2.getSearchLastReturned();
|
Date lastReturned2 = search2.getSearchLastReturned();
|
||||||
|
|
||||||
assertTrue(lastReturned2.getTime() > lastReturned1.getTime());
|
assertTrue(lastReturned2.getTime() > lastReturned1.getTime());
|
||||||
|
@ -3467,7 +3458,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSearchReusesResultsEnabledNoParams() {
|
public void testSearchReusesResultsEnabledNoParams() {
|
||||||
List<IBaseResource> resources = new ArrayList<IBaseResource>();
|
List<IBaseResource> resources = new ArrayList<>();
|
||||||
for (int i = 0; i < 50; i++) {
|
for (int i = 0; i < 50; i++) {
|
||||||
Organization org = new Organization();
|
Organization org = new Organization();
|
||||||
org.setName("HELLO");
|
org.setName("HELLO");
|
||||||
|
@ -3484,12 +3475,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
final String uuid1 = toSearchUuidFromLinkNext(result1);
|
final String uuid1 = toSearchUuidFromLinkNext(result1);
|
||||||
Search search1 = newTxTemplate().execute(new TransactionCallback<Search>() {
|
Search search1 = newTxTemplate().execute(theStatus -> mySearchEntityDao.findByUuid(uuid1));
|
||||||
@Override
|
|
||||||
public Search doInTransaction(TransactionStatus theStatus) {
|
|
||||||
return mySearchEntityDao.findByUuid(uuid1);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Date lastReturned1 = search1.getSearchLastReturned();
|
Date lastReturned1 = search1.getSearchLastReturned();
|
||||||
|
|
||||||
Bundle result2 = ourClient
|
Bundle result2 = ourClient
|
||||||
|
@ -3499,12 +3485,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
final String uuid2 = toSearchUuidFromLinkNext(result2);
|
final String uuid2 = toSearchUuidFromLinkNext(result2);
|
||||||
Search search2 = newTxTemplate().execute(new TransactionCallback<Search>() {
|
Search search2 = newTxTemplate().execute(theStatus -> mySearchEntityDao.findByUuid(uuid2));
|
||||||
@Override
|
|
||||||
public Search doInTransaction(TransactionStatus theStatus) {
|
|
||||||
return mySearchEntityDao.findByUuid(uuid2);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Date lastReturned2 = search2.getSearchLastReturned();
|
Date lastReturned2 = search2.getSearchLastReturned();
|
||||||
|
|
||||||
assertTrue(lastReturned2.getTime() > lastReturned1.getTime());
|
assertTrue(lastReturned2.getTime() > lastReturned1.getTime());
|
||||||
|
@ -3601,10 +3582,8 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
ourLog.info("** Done searching in {}ms with count of 1", sw.getMillis());
|
ourLog.info("** Done searching in {}ms with count of 1", sw.getMillis());
|
||||||
|
|
||||||
ourLog.info(myCapturingInterceptor.getLastResponse().getAllHeaders().toString());
|
ourLog.info(myCapturingInterceptor.getLastResponse().getAllHeaders().toString());
|
||||||
assertThat(myCapturingInterceptor.getLastResponse().getHeaders(Constants.HEADER_X_CACHE), Matchers.<String>empty());
|
assertThat(myCapturingInterceptor.getLastResponse().getHeaders(Constants.HEADER_X_CACHE), Matchers.empty());
|
||||||
assertThat(myCapturingInterceptor.getLastResponse().getHeaders(Constants.HEADER_X_CACHE.toLowerCase()), Matchers.<String>empty());
|
assertThat(myCapturingInterceptor.getLastResponse().getHeaders(Constants.HEADER_X_CACHE.toLowerCase()), Matchers.empty());
|
||||||
|
|
||||||
String msg = "Total is " + found.getTotalElement().getValue() + " and took " + sw.getMillis() + " millis";
|
|
||||||
|
|
||||||
// When we've only got one DB connection available, we are forced to wait for the
|
// When we've only got one DB connection available, we are forced to wait for the
|
||||||
// search to finish before returning
|
// search to finish before returning
|
||||||
|
@ -3667,8 +3646,8 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
.count(1)
|
.count(1)
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
assertThat(myCapturingInterceptor.getLastResponse().getHeaders(Constants.HEADER_X_CACHE), Matchers.<String>empty());
|
assertThat(myCapturingInterceptor.getLastResponse().getHeaders(Constants.HEADER_X_CACHE), Matchers.empty());
|
||||||
assertThat(myCapturingInterceptor.getLastResponse().getHeaders(Constants.HEADER_X_CACHE.toLowerCase()), Matchers.<String>empty());
|
assertThat(myCapturingInterceptor.getLastResponse().getHeaders(Constants.HEADER_X_CACHE.toLowerCase()), Matchers.empty());
|
||||||
|
|
||||||
// WHen we've only got one DB connection available, we are forced to wait for the
|
// WHen we've only got one DB connection available, we are forced to wait for the
|
||||||
// search to finish before returning
|
// search to finish before returning
|
||||||
|
@ -3715,7 +3694,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
Patient pat = new Patient();
|
Patient pat = new Patient();
|
||||||
pat.addIdentifier().setSystem("urn:system:rpr4").setValue("testSearchWithInclude02");
|
pat.addIdentifier().setSystem("urn:system:rpr4").setValue("testSearchWithInclude02");
|
||||||
pat.getManagingOrganization().setReferenceElement(orgId.toUnqualifiedVersionless());
|
pat.getManagingOrganization().setReferenceElement(orgId.toUnqualifiedVersionless());
|
||||||
ourClient.create().resource(pat).prettyPrint().encodedXml().execute().getId();
|
ourClient.create().resource(pat).prettyPrint().encodedXml().execute();
|
||||||
|
|
||||||
Bundle found = ourClient
|
Bundle found = ourClient
|
||||||
.search()
|
.search()
|
||||||
|
@ -3886,7 +3865,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
assertThat(ids, contains(id1.getValue()));
|
assertThat(ids, contains(id1.getValue()));
|
||||||
assertThat(ids, not(contains(id2.getValue())));
|
assertThat(ids, not(contains(id2.getValue())));
|
||||||
} finally {
|
} finally {
|
||||||
IOUtils.closeQuietly(resp);
|
resp.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3917,7 +3896,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
ourLog.info(responseContent);
|
ourLog.info(responseContent);
|
||||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||||
} finally {
|
} finally {
|
||||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
status.getEntity().getContent().close();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -4181,13 +4160,10 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
String contents = loadClasspath("/update.xml");
|
String contents = loadClasspath("/update.xml");
|
||||||
HttpPost post = new HttpPost(ourServerBase);
|
HttpPost post = new HttpPost(ourServerBase);
|
||||||
post.setEntity(new StringEntity(contents, ContentType.create("application/xml+fhir", "UTF-8")));
|
post.setEntity(new StringEntity(contents, ContentType.create("application/xml+fhir", "UTF-8")));
|
||||||
CloseableHttpResponse resp = ourHttpClient.execute(post);
|
try (CloseableHttpResponse resp = ourHttpClient.execute(post)) {
|
||||||
try {
|
|
||||||
assertEquals(200, resp.getStatusLine().getStatusCode());
|
assertEquals(200, resp.getStatusLine().getStatusCode());
|
||||||
String output = IOUtils.toString(resp.getEntity().getContent(), StandardCharsets.UTF_8);
|
String output = IOUtils.toString(resp.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||||
ourLog.info(output);
|
ourLog.info(output);
|
||||||
} finally {
|
|
||||||
resp.close();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4199,7 +4175,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
p1.setManagingOrganization(new Reference("Organization/99999999999"));
|
p1.setManagingOrganization(new Reference("Organization/99999999999"));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ourClient.create().resource(p1).execute().getId();
|
ourClient.create().resource(p1).execute();
|
||||||
fail();
|
fail();
|
||||||
} catch (InvalidRequestException e) {
|
} catch (InvalidRequestException e) {
|
||||||
assertThat(e.getMessage(), containsString("Organization/99999999999"));
|
assertThat(e.getMessage(), containsString("Organization/99999999999"));
|
||||||
|
@ -4217,16 +4193,13 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
|
|
||||||
HttpPut post = new HttpPut(ourServerBase + "/Patient");
|
HttpPut post = new HttpPut(ourServerBase + "/Patient");
|
||||||
post.setEntity(new StringEntity(resource, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
post.setEntity(new StringEntity(resource, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||||
CloseableHttpResponse response = ourHttpClient.execute(post);
|
try (CloseableHttpResponse response = ourHttpClient.execute(post)) {
|
||||||
try {
|
|
||||||
String responseString = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
String responseString = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||||
ourLog.info(responseString);
|
ourLog.info(responseString);
|
||||||
assertEquals(400, response.getStatusLine().getStatusCode());
|
assertEquals(400, response.getStatusLine().getStatusCode());
|
||||||
OperationOutcome oo = myFhirCtx.newXmlParser().parseResource(OperationOutcome.class, responseString);
|
OperationOutcome oo = myFhirCtx.newXmlParser().parseResource(OperationOutcome.class, responseString);
|
||||||
assertThat(oo.getIssue().get(0).getDiagnostics(),
|
assertThat(oo.getIssue().get(0).getDiagnostics(),
|
||||||
containsString("Can not update resource, request URL must contain an ID element for update (PUT) operation (it must be of the form [base]/[resource type]/[id])"));
|
containsString("Can not update resource, request URL must contain an ID element for update (PUT) operation (it must be of the form [base]/[resource type]/[id])"));
|
||||||
} finally {
|
|
||||||
response.close();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4241,15 +4214,12 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
|
|
||||||
HttpPut post = new HttpPut(ourServerBase + "/Patient");
|
HttpPut post = new HttpPut(ourServerBase + "/Patient");
|
||||||
post.setEntity(new StringEntity(resource, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
post.setEntity(new StringEntity(resource, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||||
CloseableHttpResponse response = ourHttpClient.execute(post);
|
try (CloseableHttpResponse response = ourHttpClient.execute(post)) {
|
||||||
try {
|
|
||||||
String responseString = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
String responseString = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||||
ourLog.info(responseString);
|
ourLog.info(responseString);
|
||||||
assertThat(responseString, containsString("Can not update resource, request URL must contain an ID element for update (PUT) operation (it must be of the form [base]/[resource type]/[id])"));
|
assertThat(responseString, containsString("Can not update resource, request URL must contain an ID element for update (PUT) operation (it must be of the form [base]/[resource type]/[id])"));
|
||||||
assertThat(responseString, containsString("<OperationOutcome"));
|
assertThat(responseString, containsString("<OperationOutcome"));
|
||||||
assertEquals(400, response.getStatusLine().getStatusCode());
|
assertEquals(400, response.getStatusLine().getStatusCode());
|
||||||
} finally {
|
|
||||||
response.close();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4267,15 +4237,12 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
|
|
||||||
HttpPut post = new HttpPut(ourServerBase + "/Patient/FOO");
|
HttpPut post = new HttpPut(ourServerBase + "/Patient/FOO");
|
||||||
post.setEntity(new StringEntity(resource, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
post.setEntity(new StringEntity(resource, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||||
CloseableHttpResponse response = ourHttpClient.execute(post);
|
try (CloseableHttpResponse response = ourHttpClient.execute(post)) {
|
||||||
try {
|
|
||||||
String responseString = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
String responseString = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||||
ourLog.info(responseString);
|
ourLog.info(responseString);
|
||||||
assertThat(responseString, containsString("Can not update resource, request URL must contain an ID element for update (PUT) operation (it must be of the form [base]/[resource type]/[id])"));
|
assertThat(responseString, containsString("Can not update resource, request URL must contain an ID element for update (PUT) operation (it must be of the form [base]/[resource type]/[id])"));
|
||||||
assertThat(responseString, containsString("<OperationOutcome"));
|
assertThat(responseString, containsString("<OperationOutcome"));
|
||||||
assertEquals(400, response.getStatusLine().getStatusCode());
|
assertEquals(400, response.getStatusLine().getStatusCode());
|
||||||
} finally {
|
|
||||||
response.close();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4481,7 +4448,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
try {
|
try {
|
||||||
assertEquals(200, response.getStatusLine().getStatusCode());
|
assertEquals(200, response.getStatusLine().getStatusCode());
|
||||||
String responseString = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
String responseString = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||||
IOUtils.closeQuietly(response.getEntity().getContent());
|
response.getEntity().getContent().close();
|
||||||
|
|
||||||
Patient respPt = myFhirCtx.newXmlParser().parseResource(Patient.class, responseString);
|
Patient respPt = myFhirCtx.newXmlParser().parseResource(Patient.class, responseString);
|
||||||
assertEquals("2", respPt.getIdElement().getVersionIdPart());
|
assertEquals("2", respPt.getIdElement().getVersionIdPart());
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
package ca.uhn.fhir.jpa.provider.r4;
|
package ca.uhn.fhir.jpa.provider.r4;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.jpa.config.TestR4Config;
|
||||||
|
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||||
import ca.uhn.fhir.jpa.search.SearchCoordinatorSvcImpl;
|
import ca.uhn.fhir.jpa.search.SearchCoordinatorSvcImpl;
|
||||||
import ca.uhn.fhir.rest.api.SummaryEnum;
|
import ca.uhn.fhir.rest.api.SummaryEnum;
|
||||||
import ca.uhn.fhir.util.TestUtil;
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
import org.hl7.fhir.r4.model.Bundle;
|
import org.hl7.fhir.r4.model.Bundle;
|
||||||
import org.hl7.fhir.r4.model.Narrative;
|
import org.hl7.fhir.r4.model.Narrative;
|
||||||
import org.hl7.fhir.r4.model.Patient;
|
import org.hl7.fhir.r4.model.Patient;
|
||||||
|
@ -11,6 +14,8 @@ import org.junit.AfterClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.test.util.AopTestUtils;
|
import org.springframework.test.util.AopTestUtils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
@SuppressWarnings("Duplicates")
|
@SuppressWarnings("Duplicates")
|
||||||
|
@ -26,6 +31,7 @@ public class ResourceProviderSummaryModeR4Test extends BaseResourceProviderR4Tes
|
||||||
myDaoConfig.setCountSearchResultsUpTo(null);
|
myDaoConfig.setCountSearchResultsUpTo(null);
|
||||||
mySearchCoordinatorSvcRaw.setLoadingThrottleForUnitTests(null);
|
mySearchCoordinatorSvcRaw.setLoadingThrottleForUnitTests(null);
|
||||||
mySearchCoordinatorSvcRaw.setSyncSizeForUnitTests(SearchCoordinatorSvcImpl.DEFAULT_SYNC_SIZE);
|
mySearchCoordinatorSvcRaw.setSyncSizeForUnitTests(SearchCoordinatorSvcImpl.DEFAULT_SYNC_SIZE);
|
||||||
|
myDaoConfig.setSearchPreFetchThresholds(new DaoConfig().getSearchPreFetchThresholds());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -34,9 +40,11 @@ public class ResourceProviderSummaryModeR4Test extends BaseResourceProviderR4Tes
|
||||||
myDaoConfig.setCountSearchResultsUpTo(5);
|
myDaoConfig.setCountSearchResultsUpTo(5);
|
||||||
|
|
||||||
mySearchCoordinatorSvcRaw = AopTestUtils.getTargetObject(mySearchCoordinatorSvc);
|
mySearchCoordinatorSvcRaw = AopTestUtils.getTargetObject(mySearchCoordinatorSvc);
|
||||||
mySearchCoordinatorSvcRaw.setLoadingThrottleForUnitTests(250);
|
mySearchCoordinatorSvcRaw.setLoadingThrottleForUnitTests(50);
|
||||||
mySearchCoordinatorSvcRaw.setSyncSizeForUnitTests(5);
|
mySearchCoordinatorSvcRaw.setSyncSizeForUnitTests(5);
|
||||||
|
|
||||||
|
myDaoConfig.setSearchPreFetchThresholds(Lists.newArrayList(20, 50, -1));
|
||||||
|
|
||||||
runInTransaction(() -> {
|
runInTransaction(() -> {
|
||||||
for (int i = 0; i < 104; i++) {
|
for (int i = 0; i < 104; i++) {
|
||||||
Patient p = new Patient();
|
Patient p = new Patient();
|
||||||
|
|
|
@ -422,6 +422,10 @@ public class SearchCoordinatorSvcImplTest {
|
||||||
return myWrap.next();
|
return myWrap.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSkippedCount() {
|
||||||
|
return myWrap.getSkippedCount();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ResultIterator extends BaseIterator<Long> implements IResultIterator {
|
public static class ResultIterator extends BaseIterator<Long> implements IResultIterator {
|
||||||
|
@ -441,16 +445,29 @@ public class SearchCoordinatorSvcImplTest {
|
||||||
public Long next() {
|
public Long next() {
|
||||||
return myWrap.next();
|
return myWrap.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSkippedCount() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class SlowIterator extends BaseIterator<Long> implements IResultIterator {
|
public static class SlowIterator extends BaseIterator<Long> implements IResultIterator {
|
||||||
|
|
||||||
|
private final IResultIterator myResultIteratorWrap;
|
||||||
private int myDelay;
|
private int myDelay;
|
||||||
private Iterator<Long> myWrap;
|
private Iterator<Long> myWrap;
|
||||||
|
|
||||||
public SlowIterator(Iterator<Long> theWrap, int theDelay) {
|
public SlowIterator(Iterator<Long> theWrap, int theDelay) {
|
||||||
myWrap = theWrap;
|
myWrap = theWrap;
|
||||||
myDelay = theDelay;
|
myDelay = theDelay;
|
||||||
|
myResultIteratorWrap = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SlowIterator(IResultIterator theWrap, int theDelay) {
|
||||||
|
myWrap = theWrap;
|
||||||
|
myResultIteratorWrap = theWrap;
|
||||||
|
myDelay = theDelay;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -468,6 +485,15 @@ public class SearchCoordinatorSvcImplTest {
|
||||||
return myWrap.next();
|
return myWrap.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSkippedCount() {
|
||||||
|
if (myResultIteratorWrap == null) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return myResultIteratorWrap.getSkippedCount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterClass
|
@AfterClass
|
||||||
|
|
|
@ -184,6 +184,10 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks<VersionEnum> {
|
||||||
.addIndex("IDX_SP_STRING_HASH_NRM")
|
.addIndex("IDX_SP_STRING_HASH_NRM")
|
||||||
.unique(false)
|
.unique(false)
|
||||||
.withColumns("HASH_NORM_PREFIX", "SP_VALUE_NORMALIZED");
|
.withColumns("HASH_NORM_PREFIX", "SP_VALUE_NORMALIZED");
|
||||||
|
spidxString
|
||||||
|
.addColumn("HASH_EXACT")
|
||||||
|
.nullable()
|
||||||
|
.type(AddColumnTask.ColumnTypeEnum.LONG);
|
||||||
spidxString
|
spidxString
|
||||||
.addIndex("IDX_SP_STRING_HASH_EXCT")
|
.addIndex("IDX_SP_STRING_HASH_EXCT")
|
||||||
.unique(false)
|
.unique(false)
|
||||||
|
@ -254,6 +258,10 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks<VersionEnum> {
|
||||||
.addIndex("IDX_SP_URI_HASH_IDENTITY")
|
.addIndex("IDX_SP_URI_HASH_IDENTITY")
|
||||||
.unique(false)
|
.unique(false)
|
||||||
.withColumns("HASH_IDENTITY", "SP_URI");
|
.withColumns("HASH_IDENTITY", "SP_URI");
|
||||||
|
spidxUri
|
||||||
|
.addColumn("HASH_URI")
|
||||||
|
.nullable()
|
||||||
|
.type(AddColumnTask.ColumnTypeEnum.LONG);
|
||||||
spidxUri
|
spidxUri
|
||||||
.addIndex("IDX_SP_URI_HASH_URI")
|
.addIndex("IDX_SP_URI_HASH_URI")
|
||||||
.unique(false)
|
.unique(false)
|
||||||
|
@ -290,7 +298,7 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks<VersionEnum> {
|
||||||
"where HFJ_RES_PARAM_PRESENT.HASH_PRESENCE is null";
|
"where HFJ_RES_PARAM_PRESENT.HASH_PRESENCE is null";
|
||||||
consolidateSearchParamPresenceIndexesTask.addQuery(sql, ArbitrarySqlTask.QueryModeEnum.BATCH_UNTIL_NO_MORE, t -> {
|
consolidateSearchParamPresenceIndexesTask.addQuery(sql, ArbitrarySqlTask.QueryModeEnum.BATCH_UNTIL_NO_MORE, t -> {
|
||||||
Long pid = (Long) t.get("PID");
|
Long pid = (Long) t.get("PID");
|
||||||
Boolean present = (Boolean) t.get("HASH_PRESENCE");
|
Boolean present = (Boolean) t.get("SP_PRESENT");
|
||||||
String resType = (String) t.get("RES_TYPE");
|
String resType = (String) t.get("RES_TYPE");
|
||||||
String paramName = (String) t.get("PARAM_NAME");
|
String paramName = (String) t.get("PARAM_NAME");
|
||||||
Long hash = SearchParamPresent.calculateHashPresence(resType, paramName, present);
|
Long hash = SearchParamPresent.calculateHashPresence(resType, paramName, present);
|
||||||
|
|
|
@ -731,7 +731,15 @@ public class RestfulServerUtils {
|
||||||
if (theResource == null) {
|
if (theResource == null) {
|
||||||
// No response is being returned
|
// No response is being returned
|
||||||
} else if (encodingDomainResourceAsText && theResource instanceof IResource) {
|
} else if (encodingDomainResourceAsText && theResource instanceof IResource) {
|
||||||
|
// DSTU2
|
||||||
writer.append(((IResource) theResource).getText().getDiv().getValueAsString());
|
writer.append(((IResource) theResource).getText().getDiv().getValueAsString());
|
||||||
|
} else if (encodingDomainResourceAsText && theResource instanceof IDomainResource) {
|
||||||
|
// DSTU3+
|
||||||
|
try {
|
||||||
|
writer.append(((IDomainResource) theResource).getText().getDivAsString());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new InternalErrorException(e);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
FhirVersionEnum forVersion = theResource.getStructureFhirVersionEnum();
|
FhirVersionEnum forVersion = theResource.getStructureFhirVersionEnum();
|
||||||
IParser parser = getNewParser(theServer.getFhirContext(), forVersion, theRequestDetails);
|
IParser parser = getNewParser(theServer.getFhirContext(), forVersion, theRequestDetails);
|
||||||
|
|
|
@ -215,9 +215,11 @@ public abstract class BaseResourceReturningMethodBinding extends BaseMethodBindi
|
||||||
linkPrev = RestfulServerUtils.createPagingLink(theIncludes, serverBase, searchId, theResult.getPreviousPageId(), theRequest.getParameters(), prettyPrint, theBundleType);
|
linkPrev = RestfulServerUtils.createPagingLink(theIncludes, serverBase, searchId, theResult.getPreviousPageId(), theRequest.getParameters(), prettyPrint, theBundleType);
|
||||||
}
|
}
|
||||||
} else if (searchId != null) {
|
} else if (searchId != null) {
|
||||||
|
int offset = theOffset + resourceList.size();
|
||||||
|
|
||||||
// We're doing offset pages
|
// We're doing offset pages
|
||||||
if (numTotalResults == null || theOffset + numToReturn < numTotalResults) {
|
if (numTotalResults == null || offset < numTotalResults) {
|
||||||
linkNext = (RestfulServerUtils.createPagingLink(theIncludes, serverBase, searchId, theOffset + numToReturn, numToReturn, theRequest.getParameters(), prettyPrint, theBundleType));
|
linkNext = (RestfulServerUtils.createPagingLink(theIncludes, serverBase, searchId, offset, numToReturn, theRequest.getParameters(), prettyPrint, theBundleType));
|
||||||
}
|
}
|
||||||
if (theOffset > 0) {
|
if (theOffset > 0) {
|
||||||
int start = Math.max(0, theOffset - theLimit);
|
int start = Math.max(0, theOffset - theLimit);
|
||||||
|
|
|
@ -69,23 +69,25 @@ public class SummaryEnumParameter implements IParameter {
|
||||||
retVal = null;
|
retVal = null;
|
||||||
} else if (isBlank(summary[0])) {
|
} else if (isBlank(summary[0])) {
|
||||||
retVal = null;
|
retVal = null;
|
||||||
} else if (summary.length == 1) {
|
} else if (summary.length == 1 && summary[0].indexOf(',') == -1) {
|
||||||
retVal = toCollectionOrNull(SummaryEnum.fromCode(summary[0]));
|
retVal = toCollectionOrNull(SummaryEnum.fromCode(summary[0]));
|
||||||
if (retVal == null) {
|
if (retVal == null) {
|
||||||
retVal = toCollectionOrNull(SummaryEnum.fromCode(summary[0].toLowerCase()));
|
retVal = toCollectionOrNull(SummaryEnum.fromCode(summary[0].toLowerCase()));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
retVal = new HashSet<>();
|
retVal = new HashSet<>();
|
||||||
for (String next : summary) {
|
for (String nextParamValue : summary) {
|
||||||
SummaryEnum value = SummaryEnum.fromCode(next);
|
for (String nextParamValueTok : nextParamValue.split(",")) {
|
||||||
|
SummaryEnum value = SummaryEnum.fromCode(nextParamValueTok);
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
value = SummaryEnum.fromCode(next.toLowerCase());
|
value = SummaryEnum.fromCode(nextParamValueTok.toLowerCase());
|
||||||
}
|
}
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
retVal.add(value);
|
retVal.add(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (retVal != null) {
|
if (retVal != null) {
|
||||||
if (retVal.contains(SummaryEnum.TEXT)) {
|
if (retVal.contains(SummaryEnum.TEXT)) {
|
||||||
|
|
|
@ -36,13 +36,13 @@ import ca.uhn.fhir.rest.api.SummaryEnum;
|
||||||
import ca.uhn.fhir.util.PortUtil;
|
import ca.uhn.fhir.util.PortUtil;
|
||||||
import ca.uhn.fhir.util.TestUtil;
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
|
|
||||||
public class SummaryParamTest {
|
public class SummaryParamDstu2Test {
|
||||||
|
|
||||||
private static CloseableHttpClient ourClient;
|
private static CloseableHttpClient ourClient;
|
||||||
private static FhirContext ourCtx = FhirContext.forDstu2();
|
private static FhirContext ourCtx = FhirContext.forDstu2();
|
||||||
private static SummaryEnum ourLastSummary;
|
private static SummaryEnum ourLastSummary;
|
||||||
private static List<SummaryEnum> ourLastSummaryList;
|
private static List<SummaryEnum> ourLastSummaryList;
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SummaryParamTest.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SummaryParamDstu2Test.class);
|
||||||
private static int ourPort;
|
private static int ourPort;
|
||||||
|
|
||||||
private static Server ourServer;
|
private static Server ourServer;
|
|
@ -30,12 +30,14 @@ package org.hl7.fhir.instance.model;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Generated on Wed, Jul 13, 2016 05:32+1000 for FHIR v1.0.2
|
// Generated on Wed, Jul 13, 2016 05:32+1000 for FHIR v1.0.2
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
|
import ca.uhn.fhir.model.api.annotation.*;
|
||||||
import org.hl7.fhir.exceptions.FHIRException;
|
import org.hl7.fhir.exceptions.FHIRException;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseBackboneElement;
|
import org.hl7.fhir.instance.model.api.IBaseBackboneElement;
|
||||||
|
|
||||||
import ca.uhn.fhir.model.api.annotation.*;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
/**
|
/**
|
||||||
* A request to perform an action.
|
* A request to perform an action.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -0,0 +1,362 @@
|
||||||
|
package ca.uhn.fhir.rest.server;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||||
|
import ca.uhn.fhir.rest.annotation.Read;
|
||||||
|
import ca.uhn.fhir.rest.annotation.Search;
|
||||||
|
import ca.uhn.fhir.rest.api.Constants;
|
||||||
|
import ca.uhn.fhir.rest.api.SummaryEnum;
|
||||||
|
import ca.uhn.fhir.util.PortUtil;
|
||||||
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.apache.http.HttpResponse;
|
||||||
|
import org.apache.http.client.methods.HttpGet;
|
||||||
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
|
import org.apache.http.impl.client.HttpClientBuilder;
|
||||||
|
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||||
|
import org.eclipse.jetty.server.Server;
|
||||||
|
import org.eclipse.jetty.servlet.ServletHandler;
|
||||||
|
import org.eclipse.jetty.servlet.ServletHolder;
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
import org.hl7.fhir.r4.model.IdType;
|
||||||
|
import org.hl7.fhir.r4.model.MedicationRequest;
|
||||||
|
import org.hl7.fhir.r4.model.Patient;
|
||||||
|
import org.hl7.fhir.r4.model.Reference;
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
|
||||||
|
public class SummaryParamR4Test {
|
||||||
|
|
||||||
|
private static CloseableHttpClient ourClient;
|
||||||
|
private static FhirContext ourCtx = FhirContext.forR4();
|
||||||
|
private static SummaryEnum ourLastSummary;
|
||||||
|
private static List<SummaryEnum> ourLastSummaryList;
|
||||||
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SummaryParamR4Test.class);
|
||||||
|
private static int ourPort;
|
||||||
|
|
||||||
|
private static Server ourServer;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void before() {
|
||||||
|
ourLastSummary = null;
|
||||||
|
ourLastSummaryList = null;
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
public void testReadSummaryData() throws Exception {
|
||||||
|
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1?_summary=" + SummaryEnum.DATA.getCode());
|
||||||
|
HttpResponse status = ourClient.execute(httpGet);
|
||||||
|
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||||
|
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||||
|
ourLog.info(responseContent);
|
||||||
|
|
||||||
|
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||||
|
assertEquals(Constants.CT_FHIR_XML_NEW + Constants.CHARSET_UTF8_CTSUFFIX.replace(" ", "").toLowerCase(), status.getEntity().getContentType().getValue().replace(" ", "").replace("UTF", "utf"));
|
||||||
|
assertThat(responseContent, not(containsString("<Bundle")));
|
||||||
|
assertThat(responseContent, (containsString("<Patien")));
|
||||||
|
assertThat(responseContent, not(containsString("<div>THE DIV</div>")));
|
||||||
|
assertThat(responseContent, (containsString("family")));
|
||||||
|
assertThat(responseContent, (containsString("maritalStatus")));
|
||||||
|
assertEquals(SummaryEnum.DATA, ourLastSummary);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReadSummaryText() throws Exception {
|
||||||
|
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1?_summary=" + SummaryEnum.TEXT.getCode());
|
||||||
|
HttpResponse status = ourClient.execute(httpGet);
|
||||||
|
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||||
|
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||||
|
ourLog.info(responseContent);
|
||||||
|
|
||||||
|
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||||
|
assertEquals(Constants.CT_HTML_WITH_UTF8.replace(" ", "").toLowerCase(), status.getEntity().getContentType().getValue().replace(" ", "").replace("UTF", "utf"));
|
||||||
|
assertThat(responseContent, not(containsString("<Bundle")));
|
||||||
|
assertThat(responseContent, not(containsString("<Medic")));
|
||||||
|
assertEquals("<div xmlns=\"http://www.w3.org/1999/xhtml\">THE DIV</div>", responseContent);
|
||||||
|
assertThat(responseContent, not(containsString("efer")));
|
||||||
|
assertEquals(SummaryEnum.TEXT, ourLastSummary);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReadSummaryTextWithMandatory() throws Exception {
|
||||||
|
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/MedicationRequest/1?_summary=" + SummaryEnum.TEXT.getCode());
|
||||||
|
HttpResponse status = ourClient.execute(httpGet);
|
||||||
|
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||||
|
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||||
|
ourLog.info(responseContent);
|
||||||
|
|
||||||
|
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||||
|
assertEquals(Constants.CT_HTML_WITH_UTF8.replace(" ", "").toLowerCase(), status.getEntity().getContentType().getValue().replace(" ", "").replace("UTF", "utf"));
|
||||||
|
assertThat(responseContent, not(containsString("<Bundle")));
|
||||||
|
assertThat(responseContent, not(containsString("<Patien")));
|
||||||
|
assertEquals("<div xmlns=\"http://www.w3.org/1999/xhtml\">TEXT</div>", responseContent);
|
||||||
|
assertThat(responseContent, not(containsString("family")));
|
||||||
|
assertThat(responseContent, not(containsString("maritalStatus")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReadSummaryTrue() throws Exception {
|
||||||
|
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1?_summary=" + SummaryEnum.TRUE.getCode());
|
||||||
|
HttpResponse status = ourClient.execute(httpGet);
|
||||||
|
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||||
|
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||||
|
ourLog.info(responseContent);
|
||||||
|
|
||||||
|
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||||
|
assertEquals(Constants.CT_FHIR_XML_NEW + Constants.CHARSET_UTF8_CTSUFFIX.replace(" ", "").toLowerCase(), status.getEntity().getContentType().getValue().replace(" ", "").replace("UTF", "utf"));
|
||||||
|
assertThat(responseContent, not(containsString("<Bundle")));
|
||||||
|
assertThat(responseContent, (containsString("<Patien")));
|
||||||
|
assertThat(responseContent, not(containsString("<div>THE DIV</div>")));
|
||||||
|
assertThat(responseContent, (containsString("family")));
|
||||||
|
assertThat(responseContent, not(containsString("maritalStatus")));
|
||||||
|
assertEquals(SummaryEnum.TRUE, ourLastSummary);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSearchSummaryCount() throws Exception {
|
||||||
|
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_pretty=true&_summary=" + SummaryEnum.COUNT.getCode());
|
||||||
|
HttpResponse status = ourClient.execute(httpGet);
|
||||||
|
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||||
|
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||||
|
ourLog.info(responseContent);
|
||||||
|
|
||||||
|
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||||
|
assertThat(responseContent, (containsString("<total value=\"1\"/>")));
|
||||||
|
assertThat(responseContent, not(containsString("entry")));
|
||||||
|
assertThat(responseContent, not(containsString("THE DIV")));
|
||||||
|
assertThat(responseContent, not(containsString("family")));
|
||||||
|
assertThat(responseContent, not(containsString("maritalStatus")));
|
||||||
|
assertEquals(SummaryEnum.COUNT, ourLastSummary);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSearchSummaryCountAndData() throws Exception {
|
||||||
|
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_pretty=true&_summary=" + SummaryEnum.COUNT.getCode() + "," + SummaryEnum.DATA.getCode());
|
||||||
|
HttpResponse status = ourClient.execute(httpGet);
|
||||||
|
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||||
|
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||||
|
ourLog.info(responseContent);
|
||||||
|
|
||||||
|
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||||
|
assertThat(responseContent, (containsString("<total value=\"1\"/>")));
|
||||||
|
assertThat(responseContent, (containsString("entry")));
|
||||||
|
assertThat(responseContent, not(containsString("THE DIV")));
|
||||||
|
assertThat(responseContent, (containsString("family")));
|
||||||
|
assertThat(responseContent, (containsString("maritalStatus")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSearchSummaryData() throws Exception {
|
||||||
|
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_summary=" + SummaryEnum.DATA.getCode());
|
||||||
|
HttpResponse status = ourClient.execute(httpGet);
|
||||||
|
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||||
|
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||||
|
ourLog.info(responseContent);
|
||||||
|
|
||||||
|
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||||
|
assertThat(responseContent, containsString("<Patient"));
|
||||||
|
assertThat(responseContent, not(containsString("THE DIV")));
|
||||||
|
assertThat(responseContent, containsString("family"));
|
||||||
|
assertThat(responseContent, containsString("maritalStatus"));
|
||||||
|
assertEquals(SummaryEnum.DATA, ourLastSummary);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSearchSummaryFalse() throws Exception {
|
||||||
|
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_summary=false");
|
||||||
|
HttpResponse status = ourClient.execute(httpGet);
|
||||||
|
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||||
|
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||||
|
ourLog.info(responseContent);
|
||||||
|
|
||||||
|
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||||
|
assertThat(responseContent, containsString("<Patient"));
|
||||||
|
assertThat(responseContent, containsString("THE DIV"));
|
||||||
|
assertThat(responseContent, containsString("family"));
|
||||||
|
assertThat(responseContent, containsString("maritalStatus"));
|
||||||
|
assertEquals(SummaryEnum.FALSE, ourLastSummary);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSearchSummaryText() throws Exception {
|
||||||
|
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_summary=" + SummaryEnum.TEXT.getCode());
|
||||||
|
HttpResponse status = ourClient.execute(httpGet);
|
||||||
|
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||||
|
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||||
|
ourLog.info(responseContent);
|
||||||
|
|
||||||
|
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||||
|
assertThat(responseContent, (containsString("<total value=\"1\"/>")));
|
||||||
|
assertThat(responseContent, (containsString("entry")));
|
||||||
|
assertThat(responseContent, (containsString("THE DIV")));
|
||||||
|
assertThat(responseContent, not(containsString("family")));
|
||||||
|
assertThat(responseContent, not(containsString("maritalStatus")));
|
||||||
|
assertEquals(SummaryEnum.TEXT, ourLastSummary);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSearchSummaryTextWithMandatory() throws Exception {
|
||||||
|
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/MedicationRequest?_summary=" + SummaryEnum.TEXT.getCode() + "&_pretty=true");
|
||||||
|
HttpResponse status = ourClient.execute(httpGet);
|
||||||
|
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||||
|
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||||
|
ourLog.info(responseContent);
|
||||||
|
|
||||||
|
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||||
|
assertThat(responseContent, (containsString("<total value=\"1\"/>")));
|
||||||
|
assertThat(responseContent, (containsString("entry")));
|
||||||
|
assertThat(responseContent, (containsString(">TEXT<")));
|
||||||
|
assertThat(responseContent, (containsString("Medication/123")));
|
||||||
|
assertThat(responseContent, not(containsStringIgnoringCase("note")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSearchSummaryTextMulti() throws Exception {
|
||||||
|
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=multi&_summary=" + SummaryEnum.TEXT.getCode());
|
||||||
|
HttpResponse status = ourClient.execute(httpGet);
|
||||||
|
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||||
|
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||||
|
ourLog.info(responseContent);
|
||||||
|
|
||||||
|
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||||
|
assertThat(responseContent, (containsString("<total value=\"1\"/>")));
|
||||||
|
assertThat(responseContent, (containsString("entry")));
|
||||||
|
assertThat(responseContent, (containsString("THE DIV")));
|
||||||
|
assertThat(responseContent, not(containsString("family")));
|
||||||
|
assertThat(responseContent, not(containsString("maritalStatus")));
|
||||||
|
assertThat(ourLastSummaryList, contains(SummaryEnum.TEXT));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSearchSummaryTrue() throws Exception {
|
||||||
|
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_summary=" + SummaryEnum.TRUE.getCode());
|
||||||
|
HttpResponse status = ourClient.execute(httpGet);
|
||||||
|
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||||
|
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||||
|
ourLog.info(responseContent);
|
||||||
|
|
||||||
|
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||||
|
assertThat(responseContent, containsString("<Patient"));
|
||||||
|
assertThat(responseContent, not(containsString("THE DIV")));
|
||||||
|
assertThat(responseContent, containsString("family"));
|
||||||
|
assertThat(responseContent, not(containsString("maritalStatus")));
|
||||||
|
assertEquals(SummaryEnum.TRUE, ourLastSummary);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSearchSummaryWithTextAndOthers() throws Exception {
|
||||||
|
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_summary=text&_summary=data");
|
||||||
|
HttpResponse status = ourClient.execute(httpGet);
|
||||||
|
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||||
|
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||||
|
ourLog.info(responseContent);
|
||||||
|
|
||||||
|
assertEquals(400, status.getStatusLine().getStatusCode());
|
||||||
|
assertThat(responseContent, containsString("Can not combine _summary=text with other values for _summary"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void afterClassClearContext() throws Exception {
|
||||||
|
ourServer.stop();
|
||||||
|
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void beforeClass() throws Exception {
|
||||||
|
ourPort = PortUtil.findFreePort();
|
||||||
|
ourServer = new Server(ourPort);
|
||||||
|
|
||||||
|
ServletHandler proxyHandler = new ServletHandler();
|
||||||
|
RestfulServer servlet = new RestfulServer(ourCtx);
|
||||||
|
|
||||||
|
servlet.setResourceProviders(new DummyPatientResourceProvider(), new DummyMedicationRequestProvider());
|
||||||
|
ServletHolder servletHolder = new ServletHolder(servlet);
|
||||||
|
proxyHandler.addServletWithMapping(servletHolder, "/*");
|
||||||
|
ourServer.setHandler(proxyHandler);
|
||||||
|
ourServer.start();
|
||||||
|
|
||||||
|
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
|
||||||
|
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||||
|
builder.setConnectionManager(connectionManager);
|
||||||
|
ourClient = builder.build();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class DummyMedicationRequestProvider implements IResourceProvider{
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends IBaseResource> getResourceType() {
|
||||||
|
return MedicationRequest.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Read
|
||||||
|
public MedicationRequest read(@IdParam IdType theId) {
|
||||||
|
MedicationRequest retVal = new MedicationRequest();
|
||||||
|
retVal.getText().setDivAsString("<div>TEXT</div>");
|
||||||
|
retVal.addNote().setText("NOTE");
|
||||||
|
retVal.setMedication(new Reference("Medication/123"));
|
||||||
|
retVal.setId(theId);
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Search
|
||||||
|
public List<MedicationRequest> read() {
|
||||||
|
return Arrays.asList(read(new IdType("999")));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class DummyPatientResourceProvider implements IResourceProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<Patient> getResourceType() {
|
||||||
|
return Patient.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Read
|
||||||
|
public Patient read(@IdParam IdType theId, SummaryEnum theSummary) {
|
||||||
|
ourLastSummary = theSummary;
|
||||||
|
Patient patient = new Patient();
|
||||||
|
patient.setId("Patient/1/_history/1");
|
||||||
|
patient.getText().setDivAsString("<div>THE DIV</div>");
|
||||||
|
patient.addName().setFamily("FAMILY");
|
||||||
|
patient.getMaritalStatus().addCoding().setCode("D");
|
||||||
|
return patient;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Search(queryName = "multi")
|
||||||
|
public Patient search(List<SummaryEnum> theSummary) {
|
||||||
|
ourLastSummaryList = theSummary;
|
||||||
|
Patient patient = new Patient();
|
||||||
|
patient.setId("Patient/1/_history/1");
|
||||||
|
patient.getText().setDivAsString("<div>THE DIV</div>");
|
||||||
|
patient.addName().setFamily("FAMILY");
|
||||||
|
patient.getMaritalStatus().addCoding().setCode("D");
|
||||||
|
return patient;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Search()
|
||||||
|
public Patient search(SummaryEnum theSummary) {
|
||||||
|
ourLastSummary = theSummary;
|
||||||
|
Patient patient = new Patient();
|
||||||
|
patient.setId("Patient/1/_history/1");
|
||||||
|
patient.getText().setDivAsString("<div>THE DIV</div>");
|
||||||
|
patient.addName().setFamily("FAMILY");
|
||||||
|
patient.getMaritalStatus().addCoding().setCode("D");
|
||||||
|
return patient;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -71,6 +71,11 @@
|
||||||
timezones where the date that could apply. This makes the search slightly more
|
timezones where the date that could apply. This makes the search slightly more
|
||||||
inclusive, which errs on the side of caution.
|
inclusive, which errs on the side of caution.
|
||||||
</action>
|
</action>
|
||||||
|
<action type="fix">
|
||||||
|
A bug was fixed in the JPA server $expunge operation where a database connection
|
||||||
|
could sometimes be opened and not returned to the pool immediately, leading to
|
||||||
|
pool starvation if the operation was called many times in a row.
|
||||||
|
</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