Merge branch 'philips-3.6.0'

This commit is contained in:
jamesagnew 2018-10-17 21:30:53 -04:00
commit 4819ce083b
21 changed files with 203 additions and 70 deletions

View File

@ -197,6 +197,7 @@ public class Constants {
* This is provided for testing only! Use with caution as this property may change. * This is provided for testing only! Use with caution as this property may change.
*/ */
public static final String TEST_SYSTEM_PROP_VALIDATION_RESOURCE_CACHES_MS = "TEST_SYSTEM_PROP_VALIDATION_RESOURCE_CACHES_MS"; public static final String TEST_SYSTEM_PROP_VALIDATION_RESOURCE_CACHES_MS = "TEST_SYSTEM_PROP_VALIDATION_RESOURCE_CACHES_MS";
public static final String PARAM_SEARCH_TOTAL_MODE = "_total";
static { static {
CHARSET_UTF8 = Charset.forName(CHARSET_NAME_UTF8); CHARSET_UTF8 = Charset.forName(CHARSET_NAME_UTF8);

View File

@ -0,0 +1,34 @@
package ca.uhn.fhir.rest.api;
import java.util.HashMap;
import java.util.Map;
public enum SearchTotalModeEnum {
NONE("none"),
ESTIMATED("estimated"),
ACCURATE("accurate");
private static volatile Map<String, SearchTotalModeEnum> ourCodeToEnum;
private final String myCode;
SearchTotalModeEnum(String theCode) {
myCode = theCode;
}
public String getCode() {
return myCode;
}
public static SearchTotalModeEnum fromCode(String theCode) {
Map<String, SearchTotalModeEnum> map = ourCodeToEnum;
if (map == null) {
map = new HashMap<>();
for (SearchTotalModeEnum next : values()) {
map.put(next.getCode(), next);
}
ourCodeToEnum = map;
}
return map.get(theCode);
}
}

View File

@ -67,7 +67,7 @@ public enum SummaryEnum {
public static SummaryEnum fromCode(String theCode) { public static SummaryEnum fromCode(String theCode) {
Map<String, SummaryEnum> c2s = ourCodeToSummary; Map<String, SummaryEnum> c2s = ourCodeToSummary;
if (c2s == null) { if (c2s == null) {
c2s = new HashMap<String, SummaryEnum>(); c2s = new HashMap<>();
for (SummaryEnum next : values()) { for (SummaryEnum next : values()) {
c2s.put(next.getCode(), next); c2s.put(next.getCode(), next);
} }

View File

@ -89,6 +89,6 @@ public interface IClientExecutable<T extends IClientExecutable<?,Y>, Y> {
/** /**
* Request that the server modify the response using the <code>_summary</code> param * Request that the server modify the response using the <code>_summary</code> param
*/ */
T summaryMode(SummaryEnum... theSummary); T summaryMode(SummaryEnum theSummary);
} }

View File

@ -2,7 +2,9 @@ package ca.uhn.fhir.rest.gclient;
import ca.uhn.fhir.model.api.Include; import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.rest.api.SearchStyleEnum; import ca.uhn.fhir.rest.api.SearchStyleEnum;
import ca.uhn.fhir.rest.api.SearchTotalModeEnum;
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.param.DateRangeParam; import ca.uhn.fhir.rest.param.DateRangeParam;
import org.hl7.fhir.instance.model.api.IBaseBundle; import org.hl7.fhir.instance.model.api.IBaseBundle;
@ -80,6 +82,14 @@ public interface IQuery<Y> extends IBaseQuery<IQuery<Y>>, IClientExecutable<IQue
*/ */
<B extends IBaseBundle> IQuery<B> returnBundle(Class<B> theClass); <B extends IBaseBundle> IQuery<B> returnBundle(Class<B> theClass);
/**
* Request that the server modify the response using the <code>_total</code> param
*
* THIS IS AN EXPERIMENTAL FEATURE - Use with caution, as it may be
* removed or modified in a future version.
*/
IQuery<Y> totalMode(SearchTotalModeEnum theTotalMode);
/** /**
* Add a "_revinclude" specification * Add a "_revinclude" specification
* *

View File

@ -205,7 +205,7 @@ public abstract class BaseClient implements IRestfulClient {
} }
<T> T invokeClient(FhirContext theContext, IClientResponseHandler<T> binding, BaseHttpClientInvocation clientInvocation, EncodingEnum theEncoding, Boolean thePrettyPrint, <T> T invokeClient(FhirContext theContext, IClientResponseHandler<T> binding, BaseHttpClientInvocation clientInvocation, EncodingEnum theEncoding, Boolean thePrettyPrint,
boolean theLogRequestAndResponse, List<SummaryEnum> theSummaryMode, Set<String> theSubsetElements, CacheControlDirective theCacheControlDirective) { boolean theLogRequestAndResponse, SummaryEnum theSummaryMode, Set<String> theSubsetElements, CacheControlDirective theCacheControlDirective) {
if (!myDontValidateConformance) { if (!myDontValidateConformance) {
myFactory.validateServerBaseIfConfiguredToDoSo(myUrlBase, myClient, this); myFactory.validateServerBaseIfConfiguredToDoSo(myUrlBase, myClient, this);
@ -227,8 +227,7 @@ public abstract class BaseClient implements IRestfulClient {
} }
if (theSummaryMode != null) { if (theSummaryMode != null) {
List<String> summaryModeStrings = theSummaryMode.stream().map(SummaryEnum::getCode).collect(Collectors.toList());; params.put(Constants.PARAM_SUMMARY, Collections.singletonList(theSummaryMode.getCode()));
params.put(Constants.PARAM_SUMMARY, summaryModeStrings);
} else if (mySummary != null) { } else if (mySummary != null) {
params.put(Constants.PARAM_SUMMARY, Collections.singletonList(mySummary.getCode())); params.put(Constants.PARAM_SUMMARY, Collections.singletonList(mySummary.getCode()));
} }

View File

@ -98,7 +98,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
} }
private <T extends IBaseResource> T doReadOrVRead(final Class<T> theType, IIdType theId, boolean theVRead, ICallable<T> theNotModifiedHandler, String theIfVersionMatches, Boolean thePrettyPrint, private <T extends IBaseResource> T doReadOrVRead(final Class<T> theType, IIdType theId, boolean theVRead, ICallable<T> theNotModifiedHandler, String theIfVersionMatches, Boolean thePrettyPrint,
List<SummaryEnum> theSummary, EncodingEnum theEncoding, Set<String> theSubsetElements) { SummaryEnum theSummary, EncodingEnum theEncoding, Set<String> theSubsetElements) {
String resName = toResourceName(theType); String resName = toResourceName(theType);
IIdType id = theId; IIdType id = theId;
if (!id.hasBaseUrl()) { if (!id.hasBaseUrl()) {
@ -127,8 +127,8 @@ public class GenericClient extends BaseClient implements IGenericClient {
invocation.addHeader(Constants.HEADER_IF_NONE_MATCH, '"' + theIfVersionMatches + '"'); invocation.addHeader(Constants.HEADER_IF_NONE_MATCH, '"' + theIfVersionMatches + '"');
} }
boolean allowHtmlResponse = (theSummary != null && theSummary.contains(SummaryEnum.TEXT)) || (theSummary == null && getSummary() == SummaryEnum.TEXT); boolean allowHtmlResponse = SummaryEnum.TEXT.equals(theSummary);
ResourceResponseHandler<T> binding = new ResourceResponseHandler<T>(theType, (Class<? extends IBaseResource>) null, id, allowHtmlResponse); ResourceResponseHandler<T> binding = new ResourceResponseHandler<>(theType, (Class<? extends IBaseResource>) null, id, allowHtmlResponse);
if (theNotModifiedHandler == null) { if (theNotModifiedHandler == null) {
return invokeClient(myContext, binding, invocation, theEncoding, thePrettyPrint, myLogRequestAndResponse, theSummary, theSubsetElements, null); return invokeClient(myContext, binding, invocation, theEncoding, thePrettyPrint, myLogRequestAndResponse, theSummary, theSubsetElements, null);
@ -368,7 +368,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
protected EncodingEnum myParamEncoding; protected EncodingEnum myParamEncoding;
protected Boolean myPrettyPrint; protected Boolean myPrettyPrint;
protected List<SummaryEnum> mySummaryMode; protected SummaryEnum mySummaryMode;
protected CacheControlDirective myCacheControlDirective; protected CacheControlDirective myCacheControlDirective;
private List<Class<? extends IBaseResource>> myPreferResponseTypes; private List<Class<? extends IBaseResource>> myPreferResponseTypes;
private boolean myQueryLogRequestAndResponse; private boolean myQueryLogRequestAndResponse;
@ -483,15 +483,8 @@ public class GenericClient extends BaseClient implements IGenericClient {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
public T summaryMode(SummaryEnum... theSummary) { public T summaryMode(SummaryEnum theSummary) {
mySummaryMode = null; mySummaryMode = theSummary;
if (theSummary != null) {
if (theSummary.length == 1) {
mySummaryMode = Collections.singletonList(theSummary[0]);
} else {
mySummaryMode = Arrays.asList(theSummary);
}
}
return ((T) this); return ((T) this);
} }
@ -1657,20 +1650,21 @@ public class GenericClient extends BaseClient implements IGenericClient {
private class SearchInternal<OUTPUT> extends BaseSearch<IQuery<OUTPUT>, IQuery<OUTPUT>, OUTPUT> implements IQuery<OUTPUT>, IUntypedQuery<IQuery<OUTPUT>> { private class SearchInternal<OUTPUT> extends BaseSearch<IQuery<OUTPUT>, IQuery<OUTPUT>, OUTPUT> implements IQuery<OUTPUT>, IUntypedQuery<IQuery<OUTPUT>> {
private String myCompartmentName; private String myCompartmentName;
private List<Include> myInclude = new ArrayList<Include>(); private List<Include> myInclude = new ArrayList<>();
private DateRangeParam myLastUpdated; private DateRangeParam myLastUpdated;
private Integer myParamLimit; private Integer myParamLimit;
private List<Collection<String>> myProfiles = new ArrayList<Collection<String>>(); private List<Collection<String>> myProfiles = new ArrayList<>();
private String myResourceId; private String myResourceId;
private String myResourceName; private String myResourceName;
private Class<? extends IBaseResource> myResourceType; private Class<? extends IBaseResource> myResourceType;
private Class<? extends IBaseBundle> myReturnBundleType; private Class<? extends IBaseBundle> myReturnBundleType;
private List<Include> myRevInclude = new ArrayList<Include>(); private List<Include> myRevInclude = new ArrayList<>();
private SearchStyleEnum mySearchStyle; private SearchStyleEnum mySearchStyle;
private String mySearchUrl; private String mySearchUrl;
private List<TokenParam> mySecurity = new ArrayList<TokenParam>(); private List<TokenParam> mySecurity = new ArrayList<>();
private List<SortInternal> mySort = new ArrayList<SortInternal>(); private List<SortInternal> mySort = new ArrayList<>();
private List<TokenParam> myTags = new ArrayList<TokenParam>(); private List<TokenParam> myTags = new ArrayList<>();
private SearchTotalModeEnum myTotalMode;
public SearchInternal() { public SearchInternal() {
myResourceType = null; myResourceType = null;
@ -1792,6 +1786,10 @@ public class GenericClient extends BaseClient implements IGenericClient {
} }
} }
if (myTotalMode != null) {
addParam(params, Constants.PARAM_SEARCH_TOTAL_MODE, myTotalMode.getCode());
}
IClientResponseHandler<? extends IBase> binding; IClientResponseHandler<? extends IBase> binding;
binding = new ResourceResponseHandler(myReturnBundleType, getPreferResponseTypes(myResourceType)); binding = new ResourceResponseHandler(myReturnBundleType, getPreferResponseTypes(myResourceType));
@ -1843,6 +1841,12 @@ public class GenericClient extends BaseClient implements IGenericClient {
return count(theLimitTo); return count(theLimitTo);
} }
@Override
public IQuery<OUTPUT> totalMode(SearchTotalModeEnum theSearchTotalModeEnum) {
myTotalMode = theSearchTotalModeEnum;
return this;
}
@Override @Override
public IQuery returnBundle(Class theClass) { public IQuery returnBundle(Class theClass) {
if (theClass == null) { if (theClass == null) {

View File

@ -5,10 +5,7 @@ import ca.uhn.fhir.model.api.IQueryParameterAnd;
import ca.uhn.fhir.model.api.IQueryParameterOr; import ca.uhn.fhir.model.api.IQueryParameterOr;
import ca.uhn.fhir.model.api.IQueryParameterType; import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.model.api.Include; import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.rest.api.Constants; import ca.uhn.fhir.rest.api.*;
import ca.uhn.fhir.rest.api.SortOrderEnum;
import ca.uhn.fhir.rest.api.SortSpec;
import ca.uhn.fhir.rest.api.SummaryEnum;
import ca.uhn.fhir.rest.param.DateParam; import ca.uhn.fhir.rest.param.DateParam;
import ca.uhn.fhir.rest.param.DateRangeParam; import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.util.ObjectUtil; import ca.uhn.fhir.util.ObjectUtil;
@ -54,7 +51,8 @@ public class SearchParameterMap extends LinkedHashMap<String, List<List<? extend
private Integer myLoadSynchronousUpTo; private Integer myLoadSynchronousUpTo;
private Set<Include> myRevIncludes; private Set<Include> myRevIncludes;
private SortSpec mySort; private SortSpec mySort;
private Set<SummaryEnum> mySummaryMode; private SummaryEnum mySummaryMode;
private SearchTotalModeEnum mySearchTotalMode;
/** /**
* Constructor * Constructor
@ -70,20 +68,22 @@ public class SearchParameterMap extends LinkedHashMap<String, List<List<? extend
add(theName, theParam); add(theName, theParam);
} }
/** public SummaryEnum getSummaryMode() {
* @return An unmodifiable set return mySummaryMode;
*/
public Set<SummaryEnum> getSummaryMode() {
if (mySummaryMode == null) {
return Collections.emptySet();
}
return Collections.unmodifiableSet(mySummaryMode);
} }
public void setSummaryMode(Set<SummaryEnum> theSummaryMode) { public void setSummaryMode(SummaryEnum theSummaryMode) {
mySummaryMode = theSummaryMode; mySummaryMode = theSummaryMode;
} }
public SearchTotalModeEnum getSearchTotalMode() {
return mySearchTotalMode;
}
public void setSearchTotalMode(SearchTotalModeEnum theSearchTotalMode) {
mySearchTotalMode = theSearchTotalMode;
}
public SearchParameterMap add(String theName, DateParam theDateParam) { public SearchParameterMap add(String theName, DateParam theDateParam) {
add(theName, (IQueryParameterOr<?>) theDateParam); add(theName, (IQueryParameterOr<?>) theDateParam);
return this; return this;
@ -261,7 +261,7 @@ public class SearchParameterMap extends LinkedHashMap<String, List<List<? extend
/** /**
* This will only return true if all parameters have no modifier of any kind * This will only return true if all parameters have no modifier of any kind
*/ */
public boolean isAllParametersHaveNoModifier() { boolean isAllParametersHaveNoModifier() {
for (List<List<? extends IQueryParameterType>> nextParamName : values()) { for (List<List<? extends IQueryParameterType>> nextParamName : values()) {
for (List<? extends IQueryParameterType> nextAnd : nextParamName) { for (List<? extends IQueryParameterType> nextAnd : nextParamName) {
for (IQueryParameterType nextOr : nextAnd) { for (IQueryParameterType nextOr : nextAnd) {
@ -408,12 +408,10 @@ public class SearchParameterMap extends LinkedHashMap<String, List<List<? extend
// Summary // Summary
if (getSummaryMode() != null) { if (getSummaryMode() != null) {
for (SummaryEnum next : getSummaryMode()) { addUrlParamSeparator(b);
addUrlParamSeparator(b); b.append(Constants.PARAM_SUMMARY);
b.append(Constants.PARAM_SUMMARY); b.append('=');
b.append('='); b.append(getSummaryMode().getCode());
b.append(next.getCode());
}
} }
if (b.length() == 0) { if (b.length() == 0) {
@ -489,7 +487,7 @@ public class SearchParameterMap extends LinkedHashMap<String, List<List<? extend
public class QueryParameterOrComparator implements Comparator<List<IQueryParameterType>> { public class QueryParameterOrComparator implements Comparator<List<IQueryParameterType>> {
private final FhirContext myCtx; private final FhirContext myCtx;
public QueryParameterOrComparator(FhirContext theCtx) { QueryParameterOrComparator(FhirContext theCtx) {
myCtx = theCtx; myCtx = theCtx;
} }
@ -505,7 +503,7 @@ public class SearchParameterMap extends LinkedHashMap<String, List<List<? extend
private final FhirContext myCtx; private final FhirContext myCtx;
public QueryParameterTypeComparator(FhirContext theCtx) { QueryParameterTypeComparator(FhirContext theCtx) {
myCtx = theCtx; myCtx = theCtx;
} }
@ -516,7 +514,7 @@ public class SearchParameterMap extends LinkedHashMap<String, List<List<? extend
} }
static int compare(FhirContext theCtx, IQueryParameterType theO1, IQueryParameterType theO2) { private static int compare(FhirContext theCtx, IQueryParameterType theO1, IQueryParameterType theO2) {
int retVal; int retVal;
if (theO1.getMissing() == null && theO2.getMissing() == null) { if (theO1.getMissing() == null && theO2.getMissing() == null) {
retVal = 0; retVal = 0;

View File

@ -29,6 +29,7 @@ import ca.uhn.fhir.jpa.entity.*;
import ca.uhn.fhir.model.api.Include; import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.rest.api.CacheControlDirective; import ca.uhn.fhir.rest.api.CacheControlDirective;
import ca.uhn.fhir.rest.api.Constants; import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.SearchTotalModeEnum;
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;
import ca.uhn.fhir.rest.server.IPagingProvider; import ca.uhn.fhir.rest.server.IPagingProvider;
@ -724,8 +725,8 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
* *
* before doing anything else. * before doing anything else.
*/ */
boolean wantCount = myParams.getSummaryMode().contains(SummaryEnum.COUNT); boolean wantOnlyCount = SummaryEnum.COUNT.equals(myParams.getSummaryMode());
boolean wantOnlyCount = wantCount && myParams.getSummaryMode().size() == 1; boolean wantCount = wantOnlyCount || SearchTotalModeEnum.ACCURATE.equals(myParams.getSearchTotalMode());
if (wantCount) { if (wantCount) {
ourLog.trace("Performing count"); ourLog.trace("Performing count");
ISearchBuilder sb = newSearchBuilder(); ISearchBuilder sb = newSearchBuilder();

View File

@ -478,6 +478,8 @@ public abstract class BaseSubscriptionInterceptor<S extends IBaseResource> exten
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() { TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override @Override
public void afterCommit() { public void afterCommit() {
// FIXME: remove
ourLog.info("** Sending processing message " + theMessage + " for: " + theMessage.getNewPayload(myCtx));
ourLog.trace("Sending resource modified message to processing channel"); ourLog.trace("Sending resource modified message to processing channel");
getProcessingChannel().send(new ResourceModifiedJsonMessage(theMessage)); getProcessingChannel().send(new ResourceModifiedJsonMessage(theMessage));
} }

View File

@ -132,7 +132,7 @@ public class CanonicalSubscription implements Serializable {
return retVal; return retVal;
} }
String getIdElementString() { public String getIdElementString() {
return myIdElement; return myIdElement;
} }

View File

@ -48,6 +48,13 @@ public class ResourceDeliveryMessage {
return myOperationType; return myOperationType;
} }
/**
* Constructor
*/
public ResourceDeliveryMessage() {
super();
}
public void setOperationType(ResourceModifiedMessage.OperationTypeEnum theOperationType) { public void setOperationType(ResourceModifiedMessage.OperationTypeEnum theOperationType) {
myOperationType = theOperationType; myOperationType = theOperationType;
} }

View File

@ -69,7 +69,7 @@ public class SubscriptionActivatingSubscriber {
Validate.notNull(theTaskExecutor); Validate.notNull(theTaskExecutor);
} }
public synchronized boolean activateOrRegisterSubscriptionIfRequired(final IBaseResource theSubscription) { public boolean activateOrRegisterSubscriptionIfRequired(final IBaseResource theSubscription) {
// Grab the value for "Subscription.channel.type" so we can see if this // Grab the value for "Subscription.channel.type" so we can see if this
// subscriber applies.. // subscriber applies..
String subscriptionChannelType = myCtx String subscriptionChannelType = myCtx
@ -180,7 +180,7 @@ public class SubscriptionActivatingSubscriber {
} }
private synchronized void activateAndRegisterSubscriptionIfRequiredInTransaction(IBaseResource theSubscription) { private void activateAndRegisterSubscriptionIfRequiredInTransaction(IBaseResource theSubscription) {
TransactionTemplate txTemplate = new TransactionTemplate(myTransactionManager); TransactionTemplate txTemplate = new TransactionTemplate(myTransactionManager);
txTemplate.execute(new TransactionCallbackWithoutResult() { txTemplate.execute(new TransactionCallbackWithoutResult() {
@Override @Override
@ -190,7 +190,7 @@ public class SubscriptionActivatingSubscriber {
}); });
} }
protected boolean registerSubscriptionUnlessAlreadyRegistered(IBaseResource theSubscription) { protected synchronized boolean registerSubscriptionUnlessAlreadyRegistered(IBaseResource theSubscription) {
CanonicalSubscription existingSubscription = mySubscriptionInterceptor.hasSubscription(theSubscription.getIdElement()); CanonicalSubscription existingSubscription = mySubscriptionInterceptor.hasSubscription(theSubscription.getIdElement());
CanonicalSubscription newSubscription = mySubscriptionInterceptor.canonicalize(theSubscription); CanonicalSubscription newSubscription = mySubscriptionInterceptor.canonicalize(theSubscription);

View File

@ -108,6 +108,10 @@ public class SubscriptionDeliveringRestHookSubscriber extends BaseSubscriptionDe
operation.encoded(thePayloadType); operation.encoded(thePayloadType);
} }
// FIXME: remove
ourLog.info("** This " + this + " Processing delivery message " + theMsg);
ourLog.info("Delivering {} rest-hook payload {} for {}", theMsg.getOperationType(), thePayloadResource.getIdElement().toUnqualified().getValue(), theSubscription.getIdElement(getContext()).toUnqualifiedVersionless().getValue()); ourLog.info("Delivering {} rest-hook payload {} for {}", theMsg.getOperationType(), thePayloadResource.getIdElement().toUnqualified().getValue(), theSubscription.getIdElement(getContext()).toUnqualifiedVersionless().getValue());
try { try {

View File

@ -22,15 +22,21 @@ package ca.uhn.fhir.jpa.subscription.resthook;
import ca.uhn.fhir.jpa.subscription.BaseSubscriptionInterceptor; import ca.uhn.fhir.jpa.subscription.BaseSubscriptionInterceptor;
import ca.uhn.fhir.jpa.subscription.CanonicalSubscription; import ca.uhn.fhir.jpa.subscription.CanonicalSubscription;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.messaging.MessageHandler; import org.springframework.messaging.MessageHandler;
import java.util.Optional; import java.util.Optional;
public class SubscriptionRestHookInterceptor extends BaseSubscriptionInterceptor { public class SubscriptionRestHookInterceptor extends BaseSubscriptionInterceptor {
private static final Logger ourLog = LoggerFactory.getLogger(SubscriptionRestHookInterceptor.class);
@Override @Override
protected Optional<MessageHandler> createDeliveryHandler(CanonicalSubscription theSubscription) { protected Optional<MessageHandler> createDeliveryHandler(CanonicalSubscription theSubscription) {
return Optional.of(new SubscriptionDeliveringRestHookSubscriber(getSubscriptionDao(), getChannelType(), this)); SubscriptionDeliveringRestHookSubscriber value = new SubscriptionDeliveringRestHookSubscriber(getSubscriptionDao(), getChannelType(), this);
// FIXME: remove
ourLog.info("** Creating delivery subscriber " + value + " for " + theSubscription.getIdElementString());
return Optional.of(value);
} }
@Override @Override

View File

@ -38,6 +38,7 @@ public class TestR4Config extends BaseJavaConfigR4 {
* starvation * starvation
*/ */
ourMaxThreads = (int) (Math.random() * 6.0) + 1; ourMaxThreads = (int) (Math.random() * 6.0) + 1;
ourMaxThreads = 1;
} }
private Exception myLastStackTrace; private Exception myLastStackTrace;

View File

@ -5,6 +5,7 @@ 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.jpa.search.SearchCoordinatorSvcImpl;
import ca.uhn.fhir.rest.api.SearchTotalModeEnum;
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;
@ -12,6 +13,7 @@ import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.param.TokenParam; import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.util.TestUtil; import ca.uhn.fhir.util.TestUtil;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.r4.model.Patient; import org.hl7.fhir.r4.model.Patient;
import org.junit.After; import org.junit.After;
import org.junit.AfterClass; import org.junit.AfterClass;
@ -23,6 +25,7 @@ import org.springframework.scheduling.concurrent.ThreadPoolExecutorFactoryBean;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future; import java.util.concurrent.Future;
@ -69,7 +72,7 @@ public class FhirResourceDaoR4SearchOptimizedTest extends BaseJpaR4Test {
SearchParameterMap params = new SearchParameterMap(); SearchParameterMap params = new SearchParameterMap();
params.setSort(new SortSpec(Patient.SP_NAME)); params.setSort(new SortSpec(Patient.SP_NAME));
params.setSummaryMode(Sets.newHashSet(SummaryEnum.COUNT)); params.setSummaryMode(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); ourLog.info("** Search returned UUID: {}", uuid);
@ -98,7 +101,7 @@ public class FhirResourceDaoR4SearchOptimizedTest extends BaseJpaR4Test {
// Seach with count only // Seach with count only
SearchParameterMap params = new SearchParameterMap(); SearchParameterMap params = new SearchParameterMap();
params.add(Patient.SP_NAME, new StringParam("FAM")); params.add(Patient.SP_NAME, new StringParam("FAM"));
params.setSummaryMode(Sets.newHashSet(SummaryEnum.COUNT)); params.setSummaryMode((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); ourLog.info("** Search returned UUID: {}", uuid);
@ -107,10 +110,10 @@ public class FhirResourceDaoR4SearchOptimizedTest extends BaseJpaR4Test {
assertThat(ids, empty()); assertThat(ids, empty());
assertEquals(201, myDatabaseBackedPagingProvider.retrieveResultList(uuid).size().intValue()); assertEquals(201, myDatabaseBackedPagingProvider.retrieveResultList(uuid).size().intValue());
// Seach with count and dat // Seach with total expicitly requested
params = new SearchParameterMap(); params = new SearchParameterMap();
params.add(Patient.SP_NAME, new StringParam("FAM")); params.add(Patient.SP_NAME, new StringParam("FAM"));
params.setSummaryMode(Sets.newHashSet(SummaryEnum.COUNT, SummaryEnum.DATA)); params.setSearchTotalMode(SearchTotalModeEnum.ACCURATE);
results = myPatientDao.search(params); results = myPatientDao.search(params);
uuid = results.getUuid(); uuid = results.getUuid();
ourLog.info("** Search returned UUID: {}", uuid); ourLog.info("** Search returned UUID: {}", uuid);
@ -122,7 +125,7 @@ public class FhirResourceDaoR4SearchOptimizedTest extends BaseJpaR4Test {
// Seach with count only // Seach with count only
params = new SearchParameterMap(); params = new SearchParameterMap();
params.add(Patient.SP_NAME, new StringParam().setMissing(false)); params.add(Patient.SP_NAME, new StringParam().setMissing(false));
params.setSummaryMode(Sets.newHashSet(SummaryEnum.COUNT)); params.setSummaryMode(SummaryEnum.COUNT);
results = myPatientDao.search(params); results = myPatientDao.search(params);
uuid = results.getUuid(); uuid = results.getUuid();
ourLog.info("** Search returned UUID: {}", uuid); ourLog.info("** Search returned UUID: {}", uuid);
@ -134,7 +137,7 @@ public class FhirResourceDaoR4SearchOptimizedTest extends BaseJpaR4Test {
} }
@Test @Test
public void testFetchCountAndDataForSlowLoading() { public void testFetchTotalAccurateForSlowLoading() {
mySearchCoordinatorSvcImpl.setLoadingThrottleForUnitTests(25); mySearchCoordinatorSvcImpl.setLoadingThrottleForUnitTests(25);
mySearchCoordinatorSvcImpl.setSyncSizeForUnitTests(10); mySearchCoordinatorSvcImpl.setSyncSizeForUnitTests(10);
@ -143,7 +146,7 @@ public class FhirResourceDaoR4SearchOptimizedTest extends BaseJpaR4Test {
SearchParameterMap params = new SearchParameterMap(); SearchParameterMap params = new SearchParameterMap();
params.setSort(new SortSpec(Patient.SP_NAME)); params.setSort(new SortSpec(Patient.SP_NAME));
params.setCount(5); params.setCount(5);
params.setSummaryMode(Sets.newHashSet(SummaryEnum.COUNT, SummaryEnum.DATA)); params.setSearchTotalMode(SearchTotalModeEnum.ACCURATE);
IBundleProvider results = myPatientDao.search(params); IBundleProvider results = myPatientDao.search(params);
String uuid = results.getUuid(); String uuid = results.getUuid();
ourLog.info("** Search returned UUID: {}", uuid); ourLog.info("** Search returned UUID: {}", uuid);
@ -168,7 +171,8 @@ public class FhirResourceDaoR4SearchOptimizedTest extends BaseJpaR4Test {
SearchParameterMap params = new SearchParameterMap(); SearchParameterMap params = new SearchParameterMap();
params.setSort(new SortSpec(Patient.SP_NAME)); params.setSort(new SortSpec(Patient.SP_NAME));
params.setSummaryMode(Sets.newHashSet(SummaryEnum.COUNT, SummaryEnum.DATA)); params.setSearchTotalMode(SearchTotalModeEnum.ACCURATE);
params.setSummaryMode(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); ourLog.info("** Search returned UUID: {}", uuid);
@ -183,7 +187,8 @@ public class FhirResourceDaoR4SearchOptimizedTest extends BaseJpaR4Test {
params = new SearchParameterMap(); params = new SearchParameterMap();
params.setSort(new SortSpec(Patient.SP_NAME)); params.setSort(new SortSpec(Patient.SP_NAME));
params.setSummaryMode(Sets.newHashSet(SummaryEnum.COUNT, SummaryEnum.DATA)); params.setSearchTotalMode(SearchTotalModeEnum.ACCURATE);
params.setSummaryMode(SummaryEnum.DATA);
results = myPatientDao.search(params); results = myPatientDao.search(params);
uuid = results.getUuid(); uuid = results.getUuid();
ourLog.info("** Search returned UUID: {}", uuid); ourLog.info("** Search returned UUID: {}", uuid);
@ -490,6 +495,7 @@ public class FhirResourceDaoR4SearchOptimizedTest extends BaseJpaR4Test {
* 20 should be prefetched since that's the initial page size * 20 should be prefetched since that's the initial page size
*/ */
waitForSize(20, () -> runInTransaction(()-> mySearchEntityDao.findByUuid(uuid).getNumFound()));
runInTransaction(() -> { runInTransaction(() -> {
Search search = mySearchEntityDao.findByUuid(uuid); Search search = mySearchEntityDao.findByUuid(uuid);
assertEquals(20, search.getNumFound()); assertEquals(20, search.getNumFound());
@ -542,7 +548,7 @@ public class FhirResourceDaoR4SearchOptimizedTest extends BaseJpaR4Test {
SearchParameterMap params = new SearchParameterMap(); SearchParameterMap params = new SearchParameterMap();
params.setSort(new SortSpec(Patient.SP_NAME)); params.setSort(new SortSpec(Patient.SP_NAME));
params.add(Patient.SP_RES_ID, new TokenParam("PT00000")); params.add(IAnyResource.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); ourLog.info("** Search returned UUID: {}", uuid);

View File

@ -3,6 +3,7 @@ package ca.uhn.fhir.jpa.provider.r4;
import ca.uhn.fhir.jpa.config.TestR4Config; import ca.uhn.fhir.jpa.config.TestR4Config;
import ca.uhn.fhir.jpa.dao.DaoConfig; 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.SearchTotalModeEnum;
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 com.google.common.collect.Lists;
@ -79,12 +80,12 @@ public class ResourceProviderSummaryModeR4Test extends BaseResourceProviderR4Tes
* Count and data - Should include both a count and the data portions of results * Count and data - Should include both a count and the data portions of results
*/ */
@Test @Test
public void testSearchWithCountAndData() { public void testSearchWithTotalAccurate() {
Bundle outcome = ourClient Bundle outcome = ourClient
.search() .search()
.forResource(Patient.class) .forResource(Patient.class)
.where(Patient.ACTIVE.exactly().code("true")) .where(Patient.ACTIVE.exactly().code("true"))
.summaryMode(SummaryEnum.COUNT, SummaryEnum.DATA) .totalMode(SearchTotalModeEnum.ACCURATE)
.returnBundle(Bundle.class) .returnBundle(Bundle.class)
.execute(); .execute();

View File

@ -128,6 +128,8 @@ public class MethodUtil {
param = new SummaryEnumParameter(); param = new SummaryEnumParameter();
} else if (parameterType.equals(PatchTypeEnum.class)) { } else if (parameterType.equals(PatchTypeEnum.class)) {
param = new PatchTypeParameter(); param = new PatchTypeParameter();
} else if (parameterType.equals(SearchTotalModeEnum.class)) {
param = new SearchTotalModeParameter();
} else { } else {
for (int i = 0; i < annotations.length && param == null; i++) { for (int i = 0; i < annotations.length && param == null; i++) {
Annotation nextAnnotation = annotations[i]; Annotation nextAnnotation = annotations[i];

View File

@ -0,0 +1,53 @@
package ca.uhn.fhir.rest.server.method;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.SearchTotalModeEnum;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import java.lang.reflect.Method;
import java.util.Collection;
/*
* #%L
* HAPI FHIR - Server Framework
* %%
* Copyright (C) 2014 - 2018 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
class SearchTotalModeParameter implements IParameter {
@Override
public Object translateQueryParametersIntoServerArgument(RequestDetails theRequest, BaseMethodBinding<?> theMethodBinding) throws InternalErrorException, InvalidRequestException {
return getTypeForRequestOrThrowInvalidRequestException(theRequest);
}
@Override
public void initializeTypes(Method theMethod, Class<? extends Collection<?>> theOuterCollectionType, Class<? extends Collection<?>> theInnerCollectionType, Class<?> theParameterType) {
// ignore
}
public static SearchTotalModeEnum getTypeForRequestOrThrowInvalidRequestException(RequestDetails theRequest) {
String[] searchTotalModeVal = theRequest.getParameters().get(Constants.PARAM_SEARCH_TOTAL_MODE);
if (searchTotalModeVal != null && searchTotalModeVal.length > 0) {
return SearchTotalModeEnum.fromCode(searchTotalModeVal[0]);
}
return null;
}
}

View File

@ -19,6 +19,7 @@ import ca.uhn.fhir.rest.annotation.*;
import ca.uhn.fhir.rest.param.*; import ca.uhn.fhir.rest.param.*;
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.SearchTotalModeEnum;
public class ${className}ResourceProvider extends public class ${className}ResourceProvider extends
## We have specialized base classes for RPs that handle certain resource types. These ## We have specialized base classes for RPs that handle certain resource types. These
@ -133,7 +134,9 @@ public class ${className}ResourceProvider extends
@ca.uhn.fhir.rest.annotation.Count @ca.uhn.fhir.rest.annotation.Count
Integer theCount, Integer theCount,
Set<SummaryEnum> theSummaryMode SummaryEnum theSummaryMode,
SearchTotalModeEnum theSearchTotalMode
) { ) {
startRequest(theServletRequest); startRequest(theServletRequest);
@ -156,6 +159,7 @@ public class ${className}ResourceProvider extends
paramMap.setSort(theSort); paramMap.setSort(theSort);
paramMap.setCount(theCount); paramMap.setCount(theCount);
paramMap.setSummaryMode(theSummaryMode); paramMap.setSummaryMode(theSummaryMode);
paramMap.setSearchTotalMode(theSearchTotalMode);
getDao().translateRawParameters(theAdditionalRawParams, paramMap); getDao().translateRawParameters(theAdditionalRawParams, paramMap);