Compare commits
27 Commits
5d79284001
...
7166deb41e
Author | SHA1 | Date |
---|---|---|
TipzCM | 7166deb41e | |
volodymyr-korzh | fb7571185a | |
Tadgh | 919e2d2405 | |
leif stawnyczy | 012469da5b | |
leif stawnyczy | c2418163d6 | |
leif stawnyczy | 72dd5c9ab8 | |
leif stawnyczy | 57754b9e8e | |
leif stawnyczy | de0e2313d1 | |
leif stawnyczy | 30ec4256c3 | |
leif stawnyczy | 0110242f6f | |
leif stawnyczy | 534de22b04 | |
leif stawnyczy | 3392d3ee61 | |
leif stawnyczy | abb3d40576 | |
leif stawnyczy | 6eb8d3e236 | |
leif stawnyczy | a668a1b08b | |
leif stawnyczy | 0ac978ca76 | |
leif stawnyczy | 901a78f534 | |
leif stawnyczy | fe715bc681 | |
leif stawnyczy | 796147e623 | |
leif stawnyczy | 8d54801370 | |
leif stawnyczy | e8a5193c19 | |
leif stawnyczy | afde9df9a6 | |
leif stawnyczy | acab578bc5 | |
leif stawnyczy | cf2f55afbb | |
leif stawnyczy | a4b731d809 | |
leif stawnyczy | 5671c8c09b | |
leif stawnyczy | baf3933fbf |
|
@ -21,6 +21,7 @@ package ca.uhn.fhir.rest.client.api;
|
|||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.param.HttpClientRequestParameters;
|
||||
import org.hl7.fhir.instance.model.api.IBaseBinary;
|
||||
|
||||
import java.util.List;
|
||||
|
@ -60,11 +61,27 @@ public interface IHttpClient {
|
|||
*/
|
||||
IHttpRequest createBinaryRequest(FhirContext theContext, IBaseBinary theBinary);
|
||||
|
||||
@Deprecated
|
||||
IHttpRequest createGetRequest(FhirContext theContext, EncodingEnum theEncoding);
|
||||
|
||||
/**
|
||||
* Create a normal http get request
|
||||
* @param theContext TODO
|
||||
* @param theEncoding the request encoding
|
||||
* Create a normal http request. The RequestType in the parameters will determine the type.
|
||||
* @return the http request to be executed
|
||||
*/
|
||||
IHttpRequest createGetRequest(FhirContext theContext, EncodingEnum theEncoding);
|
||||
IHttpRequest createRequest(HttpClientRequestParameters theParameters);
|
||||
|
||||
void addHeadersToRequest(IHttpRequest theRequest, EncodingEnum theEncodingEnum, FhirContext theContext);
|
||||
|
||||
/**
|
||||
* Updates the client's url, as well as the conditional create/update strings/params
|
||||
* (ie, the "if None Exists" stuff)
|
||||
*
|
||||
* This is used when we reuse a client for multiple different requests
|
||||
* (ex, searches, or fetching the /metadata endpoint followed by whatever
|
||||
* the actual endpoint is, etc).
|
||||
*
|
||||
* Deprecated / Legacy clients do not use this (they create new clients for
|
||||
* every request)
|
||||
*/
|
||||
void setNewUrl(StringBuilder theUrl, String theIfNoneExistsString, Map<String, List<String>> theIfNoneExistsParams);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,178 @@
|
|||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR - Core Library
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2024 Smile CDR, Inc.
|
||||
* %%
|
||||
* 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%
|
||||
*/
|
||||
package ca.uhn.fhir.rest.param;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
||||
import jakarta.annotation.Nonnull;
|
||||
import org.hl7.fhir.instance.model.api.IBaseBinary;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* This is a parameters object used for creating HttpClientRequests.
|
||||
* This will allow extensibility without constant signature changes.
|
||||
*/
|
||||
public class HttpClientRequestParameters {
|
||||
/**
|
||||
* The fhir context used.
|
||||
*/
|
||||
private FhirContext myFhirContext;
|
||||
/**
|
||||
* The encoding type (JSON, XML, etc) to use for the request.
|
||||
*/
|
||||
private EncodingEnum myEncodingEnum;
|
||||
/**
|
||||
* The request type (GET, POST, PUT, etc)
|
||||
* Generally a required field.
|
||||
*/
|
||||
private RequestTypeEnum myRequestTypeEnum;
|
||||
|
||||
/**
|
||||
* Parameters
|
||||
*/
|
||||
private Map<String, List<String>> myParams;
|
||||
|
||||
/**
|
||||
* The content type to use (application/json, etc)
|
||||
*/
|
||||
private String myContentType;
|
||||
|
||||
/**
|
||||
* If the payload is a String, this is the content to attach.
|
||||
*
|
||||
* Only one of String/byte[]/form encoded url parameters can be used.
|
||||
* String contents will be used before byte contents which will be used
|
||||
* before FormUrlEncoded parameters.
|
||||
*/
|
||||
private String myContents;
|
||||
|
||||
/**
|
||||
* If the payload is a binary, this is the binary to attach
|
||||
*/
|
||||
private IBaseBinary myBaseBinary;
|
||||
|
||||
/**
|
||||
* The URL where the request is to be made.
|
||||
*/
|
||||
private final String myUrl;
|
||||
|
||||
/**
|
||||
* If the payload is a byte[], this is the content to attach.
|
||||
*
|
||||
* Only one of String/byte[]/form encoded url parameters can be used.
|
||||
* String contents will be used before byte contents which will be used
|
||||
* before FormUrlEncoded parameters.
|
||||
*/
|
||||
private byte[] myByteContents;
|
||||
|
||||
/**
|
||||
* If the payload is a set of form encoded url parameters, these are the
|
||||
* parameters to use.
|
||||
*
|
||||
* Only one of String/byte[]/form encoded url parameters can be used.
|
||||
* String contents will be used before byte contents which will be used
|
||||
* before FormUrlEncoded parameters.
|
||||
*/
|
||||
private Map<String, List<String>> myFormParams;
|
||||
|
||||
public HttpClientRequestParameters(String theUrl, @Nonnull RequestTypeEnum theRequestTypeEnum) {
|
||||
myUrl = theUrl;
|
||||
myRequestTypeEnum = theRequestTypeEnum;
|
||||
}
|
||||
|
||||
public FhirContext getFhirContext() {
|
||||
return myFhirContext;
|
||||
}
|
||||
|
||||
public void setFhirContext(FhirContext theFhirContext) {
|
||||
myFhirContext = theFhirContext;
|
||||
}
|
||||
|
||||
public EncodingEnum getEncodingEnum() {
|
||||
return myEncodingEnum;
|
||||
}
|
||||
|
||||
public void setEncodingEnum(EncodingEnum theEncodingEnum) {
|
||||
myEncodingEnum = theEncodingEnum;
|
||||
}
|
||||
|
||||
public RequestTypeEnum getRequestTypeEnum() {
|
||||
return myRequestTypeEnum;
|
||||
}
|
||||
|
||||
public void setRequestTypeEnum(RequestTypeEnum theRequestTypeEnum) {
|
||||
myRequestTypeEnum = theRequestTypeEnum;
|
||||
}
|
||||
|
||||
public Map<String, List<String>> getParams() {
|
||||
return myParams;
|
||||
}
|
||||
|
||||
public void setParams(Map<String, List<String>> theParams) {
|
||||
myParams = theParams;
|
||||
}
|
||||
|
||||
public String getContentType() {
|
||||
return myContentType;
|
||||
}
|
||||
|
||||
public void setContentType(String theContentType) {
|
||||
myContentType = theContentType;
|
||||
}
|
||||
|
||||
public String getContents() {
|
||||
return myContents;
|
||||
}
|
||||
|
||||
public void setContents(String theContents) {
|
||||
myContents = theContents;
|
||||
}
|
||||
|
||||
public IBaseBinary getBaseBinary() {
|
||||
return myBaseBinary;
|
||||
}
|
||||
|
||||
public void setBaseBinary(IBaseBinary theBaseBinary) {
|
||||
myBaseBinary = theBaseBinary;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return myUrl;
|
||||
}
|
||||
|
||||
public byte[] getByteContents() {
|
||||
return myByteContents;
|
||||
}
|
||||
|
||||
public void setByteContents(byte[] theByteContents) {
|
||||
myByteContents = theByteContents;
|
||||
}
|
||||
|
||||
public Map<String, List<String>> getFormParams() {
|
||||
return myFormParams;
|
||||
}
|
||||
|
||||
public void setFormParams(Map<String, List<String>> theFormParams) {
|
||||
myFormParams = theFormParams;
|
||||
}
|
||||
}
|
|
@ -29,6 +29,7 @@ import ca.uhn.fhir.rest.client.api.IHttpClient;
|
|||
import ca.uhn.fhir.rest.client.api.IHttpRequest;
|
||||
import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation;
|
||||
import ca.uhn.fhir.rest.client.method.MethodUtil;
|
||||
import ca.uhn.fhir.rest.param.HttpClientRequestParameters;
|
||||
import okhttp3.Call;
|
||||
import okhttp3.FormBody;
|
||||
import okhttp3.MediaType;
|
||||
|
@ -44,6 +45,7 @@ import static ca.uhn.fhir.okhttp.utils.UrlStringUtils.endsWith;
|
|||
import static ca.uhn.fhir.okhttp.utils.UrlStringUtils.everythingAfterFirstQuestionMark;
|
||||
import static ca.uhn.fhir.okhttp.utils.UrlStringUtils.hasQuestionMark;
|
||||
import static ca.uhn.fhir.okhttp.utils.UrlStringUtils.withTrailingQuestionMarkRemoved;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
/**
|
||||
* A Http Request based on OkHttp. This is an adapter around the class
|
||||
|
@ -52,6 +54,7 @@ import static ca.uhn.fhir.okhttp.utils.UrlStringUtils.withTrailingQuestionMarkRe
|
|||
* @author Matthew Clarke | matthew.clarke@orionhealth.com | Orion Health
|
||||
*/
|
||||
public class OkHttpRestfulClient implements IHttpClient {
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(OkHttpRestfulClient.class);
|
||||
|
||||
private Call.Factory myClient;
|
||||
private StringBuilder myUrl;
|
||||
|
@ -79,13 +82,15 @@ public class OkHttpRestfulClient implements IHttpClient {
|
|||
@Override
|
||||
public IHttpRequest createByteRequest(
|
||||
FhirContext theContext, String theContents, String theContentType, EncodingEnum theEncoding) {
|
||||
initBaseRequest(theContext, theEncoding, createPostBody(theContents, theContentType));
|
||||
initBaseRequest(theContext, theEncoding, createPostBody(theContents, theContentType), RequestTypeEnum.POST);
|
||||
return myRequest;
|
||||
}
|
||||
|
||||
private void initBaseRequest(FhirContext theContext, EncodingEnum theEncoding, RequestBody body) {
|
||||
private void initBaseRequest(
|
||||
FhirContext theContext, EncodingEnum theEncoding, RequestBody body, RequestTypeEnum theRequestType) {
|
||||
RequestTypeEnum requestType = theRequestType != null ? theRequestType : myRequestType;
|
||||
String sanitisedUrl = withTrailingQuestionMarkRemoved(myUrl.toString());
|
||||
myRequest = new OkHttpRestfulRequest(myClient, sanitisedUrl, myRequestType, body);
|
||||
myRequest = new OkHttpRestfulRequest(myClient, sanitisedUrl, requestType, body);
|
||||
addHeadersToRequest(myRequest, theEncoding, theContext);
|
||||
}
|
||||
|
||||
|
@ -96,7 +101,7 @@ public class OkHttpRestfulClient implements IHttpClient {
|
|||
@Override
|
||||
public IHttpRequest createParamRequest(
|
||||
FhirContext theContext, Map<String, List<String>> theParams, EncodingEnum theEncoding) {
|
||||
initBaseRequest(theContext, theEncoding, getFormBodyFromParams(theParams));
|
||||
initBaseRequest(theContext, theEncoding, getFormBodyFromParams(theParams), RequestTypeEnum.POST);
|
||||
return myRequest;
|
||||
}
|
||||
|
||||
|
@ -113,7 +118,11 @@ public class OkHttpRestfulClient implements IHttpClient {
|
|||
|
||||
@Override
|
||||
public IHttpRequest createBinaryRequest(FhirContext theContext, IBaseBinary theBinary) {
|
||||
initBaseRequest(theContext, null, createPostBody(theBinary.getContent(), theBinary.getContentType()));
|
||||
initBaseRequest(
|
||||
theContext,
|
||||
null,
|
||||
createPostBody(theBinary.getContent(), theBinary.getContentType()),
|
||||
RequestTypeEnum.POST);
|
||||
return myRequest;
|
||||
}
|
||||
|
||||
|
@ -123,10 +132,55 @@ public class OkHttpRestfulClient implements IHttpClient {
|
|||
|
||||
@Override
|
||||
public IHttpRequest createGetRequest(FhirContext theContext, EncodingEnum theEncoding) {
|
||||
initBaseRequest(theContext, theEncoding, null);
|
||||
initBaseRequest(theContext, theEncoding, null, RequestTypeEnum.GET);
|
||||
return myRequest;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IHttpRequest createRequest(HttpClientRequestParameters theParameters) {
|
||||
RequestBody requestBody = null;
|
||||
switch (theParameters.getRequestTypeEnum()) {
|
||||
case POST:
|
||||
case PUT:
|
||||
if (theParameters.getFormParams() != null
|
||||
&& !theParameters.getFormParams().isEmpty()) {
|
||||
requestBody = getFormBodyFromParams(theParameters.getFormParams());
|
||||
} else if (theParameters.getByteContents() != null) {
|
||||
requestBody = createPostBody(theParameters.getByteContents(), theParameters.getContentType());
|
||||
} else if (isNotBlank(theParameters.getContents())) {
|
||||
requestBody = createPostBody(theParameters.getContents(), theParameters.getContentType());
|
||||
} else if (theParameters.getBaseBinary() != null) {
|
||||
requestBody =
|
||||
createPostBody(theParameters.getBaseBinary().getContent(), theParameters.getContentType());
|
||||
} else {
|
||||
ourLog.debug(
|
||||
"No body contents found for HTTP-{}",
|
||||
theParameters.getRequestTypeEnum().name());
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
initBaseRequest(
|
||||
theParameters.getFhirContext(),
|
||||
theParameters.getEncodingEnum(),
|
||||
requestBody,
|
||||
theParameters.getRequestTypeEnum());
|
||||
return myRequest;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addHeadersToRequest(IHttpRequest theRequest, EncodingEnum theEncodingEnum, FhirContext theContext) {
|
||||
// not needed for this client
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNewUrl(
|
||||
StringBuilder theUrl, String theIfNoneExistString, Map<String, List<String>> theIfNoneExistParams) {
|
||||
myUrl = theUrl;
|
||||
myIfNoneExistString = theIfNoneExistString;
|
||||
myIfNoneExistParams = theIfNoneExistParams;
|
||||
}
|
||||
|
||||
private void addHeadersToRequest(
|
||||
OkHttpRestfulRequest theHttpRequest, EncodingEnum theEncoding, FhirContext theContext) {
|
||||
if (myHeaders != null) {
|
||||
|
|
|
@ -25,6 +25,7 @@ import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
|||
import ca.uhn.fhir.rest.client.api.Header;
|
||||
import ca.uhn.fhir.rest.client.api.IHttpClient;
|
||||
import ca.uhn.fhir.rest.client.api.IHttpRequest;
|
||||
import ca.uhn.fhir.rest.param.HttpClientRequestParameters;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.NameValuePair;
|
||||
|
@ -46,6 +47,8 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
/**
|
||||
* A Http Client based on Apache. This is an adapter around the class
|
||||
* {@link org.apache.http.client.HttpClient HttpClient}
|
||||
|
@ -67,9 +70,35 @@ public class ApacheHttpClient extends BaseHttpClient implements IHttpClient {
|
|||
this.myClient = theClient;
|
||||
}
|
||||
|
||||
private HttpRequestBase constructRequestBase(HttpEntity theEntity) {
|
||||
String url = myUrl.toString();
|
||||
switch (myRequestType) {
|
||||
private HttpEntity getEntityFromParameters(HttpClientRequestParameters theParameters) {
|
||||
if (isNotBlank(theParameters.getContents())) {
|
||||
return new ByteArrayEntity(theParameters.getContents().getBytes(Constants.CHARSET_UTF8));
|
||||
} else if (theParameters.getByteContents() != null) {
|
||||
return new ByteArrayEntity(theParameters.getByteContents());
|
||||
} else if (theParameters.getFormParams() != null
|
||||
&& !theParameters.getFormParams().isEmpty()) {
|
||||
return entityFromFormParams(theParameters.getFormParams());
|
||||
}
|
||||
/*
|
||||
* Could be a get request.
|
||||
* This fallthrough is for legacy purposes; ideally we would use the request type
|
||||
* but legacy clients don't have it defined always.
|
||||
*/
|
||||
return null;
|
||||
}
|
||||
|
||||
private HttpRequestBase constructRequestBase(HttpClientRequestParameters theParameters, HttpEntity theEntity) {
|
||||
// we default to the parameters request type;
|
||||
// but if that's not provided (as in legacy clients case)
|
||||
// we'll use the client's request type instead.
|
||||
// one of these will definitely be provided though.
|
||||
RequestTypeEnum requestTypeEnum = theParameters.getRequestTypeEnum();
|
||||
if (requestTypeEnum == null) {
|
||||
requestTypeEnum = myRequestType;
|
||||
}
|
||||
assert requestTypeEnum != null : "Request type required";
|
||||
String url = theParameters.getUrl();
|
||||
switch (requestTypeEnum) {
|
||||
case DELETE:
|
||||
return new HttpDelete(url);
|
||||
case PATCH:
|
||||
|
@ -92,6 +121,13 @@ public class ApacheHttpClient extends BaseHttpClient implements IHttpClient {
|
|||
}
|
||||
}
|
||||
|
||||
private HttpRequestBase constructRequestBase(HttpEntity theEntity) {
|
||||
// request type for requests with bodies is POST
|
||||
RequestTypeEnum requestType = myRequestType == null ? RequestTypeEnum.POST : myRequestType;
|
||||
HttpClientRequestParameters parameters = new HttpClientRequestParameters(myUrl.toString(), requestType);
|
||||
return constructRequestBase(parameters, theEntity);
|
||||
}
|
||||
|
||||
private UrlEncodedFormEntity createFormEntity(List<NameValuePair> parameters) {
|
||||
try {
|
||||
return new UrlEncodedFormEntity(parameters, "UTF-8");
|
||||
|
@ -100,6 +136,13 @@ public class ApacheHttpClient extends BaseHttpClient implements IHttpClient {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IHttpRequest createRequest(HttpClientRequestParameters theParameters) {
|
||||
myUrl = new StringBuilder(theParameters.getUrl());
|
||||
HttpRequestBase request = constructRequestBase(theParameters, getEntityFromParameters(theParameters));
|
||||
return new ApacheHttpRequest(myClient, request);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IHttpRequest createHttpRequest() {
|
||||
return createHttpRequest((HttpEntity) null);
|
||||
|
@ -123,6 +166,11 @@ public class ApacheHttpClient extends BaseHttpClient implements IHttpClient {
|
|||
|
||||
@Override
|
||||
protected IHttpRequest createHttpRequest(Map<String, List<String>> theParams) {
|
||||
UrlEncodedFormEntity entity = entityFromFormParams(theParams);
|
||||
return createHttpRequest(entity);
|
||||
}
|
||||
|
||||
private UrlEncodedFormEntity entityFromFormParams(Map<String, List<String>> theParams) {
|
||||
List<NameValuePair> parameters = new ArrayList<>();
|
||||
for (Entry<String, List<String>> nextParam : theParams.entrySet()) {
|
||||
List<String> value = nextParam.getValue();
|
||||
|
@ -132,7 +180,7 @@ public class ApacheHttpClient extends BaseHttpClient implements IHttpClient {
|
|||
}
|
||||
|
||||
UrlEncodedFormEntity entity = createFormEntity(parameters);
|
||||
return createHttpRequest(entity);
|
||||
return entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -50,8 +50,8 @@ import java.util.Map;
|
|||
*/
|
||||
public class ApacheHttpRequest extends BaseHttpRequest implements IHttpRequest {
|
||||
|
||||
private HttpClient myClient;
|
||||
private HttpRequestBase myRequest;
|
||||
private final HttpClient myClient;
|
||||
private final HttpRequestBase myRequest;
|
||||
|
||||
public ApacheHttpRequest(HttpClient theClient, HttpRequestBase theApacheRequest) {
|
||||
this.myClient = theClient;
|
||||
|
|
|
@ -87,13 +87,10 @@ public class ApacheRestfulClientFactory extends RestfulClientFactory {
|
|||
|
||||
public HttpClient getNativeHttpClient() {
|
||||
if (myHttpClient == null) {
|
||||
|
||||
// TODO: Use of a deprecated method should be resolved.
|
||||
RequestConfig defaultRequestConfig = RequestConfig.custom()
|
||||
.setSocketTimeout(getSocketTimeout())
|
||||
.setConnectTimeout(getConnectTimeout())
|
||||
.setConnectionRequestTimeout(getConnectionRequestTimeout())
|
||||
.setStaleConnectionCheckEnabled(true)
|
||||
.setProxy(myProxy)
|
||||
.build();
|
||||
|
||||
|
@ -106,6 +103,10 @@ public class ApacheRestfulClientFactory extends RestfulClientFactory {
|
|||
new PoolingHttpClientConnectionManager(getConnectionTimeToLive(), TimeUnit.MILLISECONDS);
|
||||
connectionManager.setMaxTotal(getPoolMaxTotal());
|
||||
connectionManager.setDefaultMaxPerRoute(getPoolMaxPerRoute());
|
||||
// default value for stale connection check
|
||||
// this can be disabled (with a -ve value) if performance is bad
|
||||
// but currently we are using the default for whatever reason
|
||||
connectionManager.setValidateAfterInactivity(2000);
|
||||
builder.setConnectionManager(connectionManager);
|
||||
|
||||
if (myProxy != null && isNotBlank(getProxyUsername()) && isNotBlank(getProxyPassword())) {
|
||||
|
|
|
@ -29,6 +29,7 @@ import ca.uhn.fhir.rest.client.api.IHttpClient;
|
|||
import ca.uhn.fhir.rest.client.api.IHttpRequest;
|
||||
import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation;
|
||||
import ca.uhn.fhir.rest.client.method.MethodUtil;
|
||||
import ca.uhn.fhir.rest.param.HttpClientRequestParameters;
|
||||
import org.hl7.fhir.instance.model.api.IBaseBinary;
|
||||
|
||||
import java.util.List;
|
||||
|
@ -37,10 +38,10 @@ import java.util.Map;
|
|||
public abstract class BaseHttpClient implements IHttpClient {
|
||||
|
||||
private final List<Header> myHeaders;
|
||||
private final Map<String, List<String>> myIfNoneExistParams;
|
||||
private final String myIfNoneExistString;
|
||||
protected final RequestTypeEnum myRequestType;
|
||||
protected final StringBuilder myUrl;
|
||||
private Map<String, List<String>> myIfNoneExistParams;
|
||||
private String myIfNoneExistString;
|
||||
protected RequestTypeEnum myRequestType;
|
||||
protected StringBuilder myUrl;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
|
@ -58,6 +59,14 @@ public abstract class BaseHttpClient implements IHttpClient {
|
|||
this.myHeaders = theHeaders;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNewUrl(
|
||||
StringBuilder theUrl, String theIfNoneExistString, Map<String, List<String>> theIfNoneExistParams) {
|
||||
myUrl = theUrl;
|
||||
myIfNoneExistString = theIfNoneExistString;
|
||||
myIfNoneExistParams = theIfNoneExistParams;
|
||||
}
|
||||
|
||||
private void addHeaderIfNoneExist(IHttpRequest result) {
|
||||
if (myIfNoneExistParams != null) {
|
||||
StringBuilder b = newHeaderBuilder(myUrl);
|
||||
|
@ -108,11 +117,12 @@ public abstract class BaseHttpClient implements IHttpClient {
|
|||
|
||||
@Override
|
||||
public IHttpRequest createGetRequest(FhirContext theContext, EncodingEnum theEncoding) {
|
||||
IHttpRequest retVal = createHttpRequest();
|
||||
IHttpRequest retVal = createRequest(new HttpClientRequestParameters(myUrl.toString(), RequestTypeEnum.GET));
|
||||
addHeadersToRequest(retVal, theEncoding, theContext);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
protected abstract IHttpRequest createHttpRequest();
|
||||
|
||||
protected abstract IHttpRequest createHttpRequest(byte[] theContent);
|
||||
|
|
|
@ -51,6 +51,8 @@ import ca.uhn.fhir.rest.client.method.HttpGetClientInvocation;
|
|||
import ca.uhn.fhir.rest.client.method.IClientResponseHandler;
|
||||
import ca.uhn.fhir.rest.client.method.IClientResponseHandlerHandlesBinary;
|
||||
import ca.uhn.fhir.rest.client.method.MethodUtil;
|
||||
import ca.uhn.fhir.rest.client.model.AsHttpRequestParams;
|
||||
import ca.uhn.fhir.rest.client.model.InvokeClientParameters;
|
||||
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.system.HapiSystemProperties;
|
||||
|
@ -88,7 +90,7 @@ public abstract class BaseClient implements IRestfulClient {
|
|||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseClient.class);
|
||||
|
||||
private final IHttpClient myClient;
|
||||
protected IHttpClient myClient;
|
||||
private final RestfulClientFactory myFactory;
|
||||
private final String myUrlBase;
|
||||
private boolean myDontValidateConformance;
|
||||
|
@ -267,6 +269,32 @@ public abstract class BaseClient implements IRestfulClient {
|
|||
CacheControlDirective theCacheControlDirective,
|
||||
String theCustomAcceptHeader,
|
||||
Map<String, List<String>> theCustomHeaders) {
|
||||
return this.invokeClient(new InvokeClientParameters<T>()
|
||||
.setContext(theContext)
|
||||
.setBinding(binding)
|
||||
.setClientInvocation(clientInvocation)
|
||||
.setEncoding(theEncoding)
|
||||
.setPrettyPrint(thePrettyPrint)
|
||||
.setTheLogRequestAndResponse(theLogRequestAndResponse)
|
||||
.setSummaryMode(theSummaryMode)
|
||||
.setSubsetElements(theSubsetElements)
|
||||
.setCacheControlDirective(theCacheControlDirective)
|
||||
.setCustomAcceptHeader(theCustomAcceptHeader)
|
||||
.setCustomHeaders(theCustomHeaders));
|
||||
}
|
||||
|
||||
protected <T> T invokeClient(InvokeClientParameters<T> theParameters) {
|
||||
FhirContext theContext = theParameters.getContext();
|
||||
IClientResponseHandler<T> binding = theParameters.getBinding();
|
||||
BaseHttpClientInvocation clientInvocation = theParameters.getClientInvocation();
|
||||
EncodingEnum theEncoding = theParameters.getEncoding();
|
||||
Boolean thePrettyPrint = theParameters.getPrettyPrint();
|
||||
boolean theLogRequestAndResponse = theParameters.isTheLogRequestAndResponse();
|
||||
SummaryEnum theSummaryMode = theParameters.getSummaryMode();
|
||||
Set<String> theSubsetElements = theParameters.getSubsetElements();
|
||||
CacheControlDirective theCacheControlDirective = theParameters.getCacheControlDirective();
|
||||
String theCustomAcceptHeader = theParameters.getCustomAcceptHeader();
|
||||
Map<String, List<String>> theCustomHeaders = theParameters.getCustomHeaders();
|
||||
|
||||
if (!myDontValidateConformance) {
|
||||
myFactory.validateServerBaseIfConfiguredToDoSo(myUrlBase, myClient, this);
|
||||
|
@ -299,7 +327,7 @@ public abstract class BaseClient implements IRestfulClient {
|
|||
params.put(Constants.PARAM_PRETTY, Collections.singletonList(Constants.PARAM_PRETTY_VALUE_TRUE));
|
||||
}
|
||||
|
||||
if (theSubsetElements != null && theSubsetElements.isEmpty() == false) {
|
||||
if (theSubsetElements != null && !theSubsetElements.isEmpty()) {
|
||||
params.put(
|
||||
Constants.PARAM_ELEMENTS, Collections.singletonList(StringUtils.join(theSubsetElements, ',')));
|
||||
}
|
||||
|
@ -309,7 +337,13 @@ public abstract class BaseClient implements IRestfulClient {
|
|||
encoding = theEncoding;
|
||||
}
|
||||
|
||||
httpRequest = clientInvocation.asHttpRequest(myUrlBase, params, encoding, thePrettyPrint);
|
||||
AsHttpRequestParams asHttpRequestParams = new AsHttpRequestParams()
|
||||
.setExtraParams(params)
|
||||
.setUrlBase(myUrlBase)
|
||||
.setPrettyPrint(thePrettyPrint)
|
||||
.setEncodingEnum(encoding)
|
||||
.setClient(myClient);
|
||||
httpRequest = clientInvocation.asHttpRequest(asHttpRequestParams);
|
||||
|
||||
if (isNotBlank(theCustomAcceptHeader)) {
|
||||
httpRequest.removeHeaders(Constants.HEADER_ACCEPT);
|
||||
|
|
|
@ -26,6 +26,9 @@ import ca.uhn.fhir.rest.client.api.Header;
|
|||
import ca.uhn.fhir.rest.client.api.IHttpClient;
|
||||
import ca.uhn.fhir.rest.client.api.IHttpRequest;
|
||||
import ca.uhn.fhir.rest.client.api.IRestfulClientFactory;
|
||||
import ca.uhn.fhir.rest.client.model.AsHttpRequestParams;
|
||||
import ca.uhn.fhir.rest.client.model.CreateRequestParameters;
|
||||
import ca.uhn.fhir.rest.param.HttpClientRequestParameters;
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -48,7 +51,7 @@ public abstract class BaseHttpClientInvocation {
|
|||
}
|
||||
|
||||
/**
|
||||
* Create an HTTP request out of this client request
|
||||
* Create an HTTP request out of this client request.
|
||||
*
|
||||
* @param theUrlBase
|
||||
* The FHIR server base url (with a trailing "/")
|
||||
|
@ -57,28 +60,67 @@ public abstract class BaseHttpClientInvocation {
|
|||
* @param theEncoding
|
||||
* The encoding to use for any serialized content sent to the
|
||||
* server
|
||||
*
|
||||
* @deprecated Use/Override {@link #asHttpRequest(AsHttpRequestParams)} instead.
|
||||
*/
|
||||
@Deprecated(since = "7.5.0")
|
||||
public abstract IHttpRequest asHttpRequest(
|
||||
String theUrlBase,
|
||||
Map<String, List<String>> theExtraParams,
|
||||
EncodingEnum theEncoding,
|
||||
Boolean thePrettyPrint);
|
||||
|
||||
public IHttpRequest asHttpRequest(AsHttpRequestParams theParams) {
|
||||
// default passes back to deprecated;
|
||||
// this is to allow existing clients not to break
|
||||
return asHttpRequest(
|
||||
theParams.getUrlBase(),
|
||||
theParams.getExtraParams(),
|
||||
theParams.getEncodingEnum(),
|
||||
theParams.getPrettyPrint());
|
||||
}
|
||||
|
||||
/**
|
||||
* Use {@link #createHttpRequest(CreateRequestParameters)}
|
||||
*/
|
||||
@Deprecated
|
||||
protected IHttpRequest createHttpRequest(String theUrl, EncodingEnum theEncoding, RequestTypeEnum theRequestType) {
|
||||
return createHttpRequest(new CreateRequestParameters()
|
||||
.setUrl(theUrl)
|
||||
.setEncodingEnum(theEncoding)
|
||||
.setRequestTypeEnum(theRequestType));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an HTTP request for the given url, encoding and request-type
|
||||
*
|
||||
* @param theUrl
|
||||
* The complete FHIR url to which the http request will be sent
|
||||
* @param theEncoding
|
||||
* The encoding to use for any serialized content sent to the
|
||||
* server
|
||||
* @param theRequestType
|
||||
* the type of HTTP request (GET, DELETE, ..)
|
||||
*/
|
||||
protected IHttpRequest createHttpRequest(String theUrl, EncodingEnum theEncoding, RequestTypeEnum theRequestType) {
|
||||
IHttpClient httpClient = getRestfulClientFactory()
|
||||
.getHttpClient(new StringBuilder(theUrl), null, null, theRequestType, myHeaders);
|
||||
return httpClient.createGetRequest(getContext(), theEncoding);
|
||||
protected IHttpRequest createHttpRequest(CreateRequestParameters theParameters) {
|
||||
IHttpClient httpClient;
|
||||
if (theParameters.getClient() != null) {
|
||||
// reuse existing client
|
||||
httpClient = theParameters.getClient();
|
||||
httpClient.setNewUrl(new StringBuilder(theParameters.getUrl()), null, null);
|
||||
} else {
|
||||
// make a new client
|
||||
httpClient = getRestfulClientFactory()
|
||||
.getHttpClient(
|
||||
new StringBuilder(theParameters.getUrl()),
|
||||
null,
|
||||
null,
|
||||
theParameters.getRequestTypeEnum(),
|
||||
myHeaders);
|
||||
}
|
||||
|
||||
HttpClientRequestParameters clientRequestParameters =
|
||||
new HttpClientRequestParameters(theParameters.getUrl(), theParameters.getRequestTypeEnum());
|
||||
clientRequestParameters.setEncodingEnum(theParameters.getEncodingEnum());
|
||||
clientRequestParameters.setFhirContext(getContext());
|
||||
IHttpRequest request = httpClient.createRequest(clientRequestParameters);
|
||||
for (Header h : getHeaders()) {
|
||||
request.addHeader(h.getName(), h.getValue());
|
||||
}
|
||||
httpClient.addHeadersToRequest(request, theParameters.getEncodingEnum(), getContext());
|
||||
return request;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -69,6 +69,8 @@ import ca.uhn.fhir.rest.client.method.SearchMethodBinding;
|
|||
import ca.uhn.fhir.rest.client.method.SortParameter;
|
||||
import ca.uhn.fhir.rest.client.method.TransactionMethodBinding;
|
||||
import ca.uhn.fhir.rest.client.method.ValidateMethodBindingDstu2Plus;
|
||||
import ca.uhn.fhir.rest.client.model.AsHttpRequestParams;
|
||||
import ca.uhn.fhir.rest.client.model.InvokeClientParameters;
|
||||
import ca.uhn.fhir.rest.gclient.IBaseQuery;
|
||||
import ca.uhn.fhir.rest.gclient.IClientExecutable;
|
||||
import ca.uhn.fhir.rest.gclient.ICreate;
|
||||
|
@ -179,7 +181,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
private static final String I18N_INCOMPLETE_URI_FOR_READ = GenericClient.class.getName() + ".incompleteUriForRead";
|
||||
private static final String I18N_NO_VERSION_ID_FOR_VREAD = GenericClient.class.getName() + ".noVersionIdForVread";
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(GenericClient.class);
|
||||
private FhirContext myContext;
|
||||
private final FhirContext myContext;
|
||||
private IHttpRequest myLastRequest;
|
||||
private boolean myLogRequestAndResponse;
|
||||
|
||||
|
@ -194,17 +196,17 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
|
||||
@Override
|
||||
public IFetchConformanceUntyped capabilities() {
|
||||
return new FetchConformanceInternal();
|
||||
return new FetchConformanceInternal(myClient);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICreate create() {
|
||||
return new CreateInternal();
|
||||
return new CreateInternal(myClient);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IDelete delete() {
|
||||
return new DeleteInternal();
|
||||
return new DeleteInternal(myClient);
|
||||
}
|
||||
|
||||
private <T extends IBaseResource> T doReadOrVRead(
|
||||
|
@ -240,8 +242,13 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
}
|
||||
}
|
||||
if (isKeepResponses()) {
|
||||
myLastRequest = invocation.asHttpRequest(
|
||||
getServerBase(), createExtraParams(theCustomAcceptHeaderValue), getEncoding(), isPrettyPrint());
|
||||
AsHttpRequestParams params = new AsHttpRequestParams()
|
||||
.setExtraParams(createExtraParams(theCustomAcceptHeaderValue))
|
||||
.setUrlBase(getServerBase())
|
||||
.setClient(myClient)
|
||||
.setEncodingEnum(getEncoding())
|
||||
.setPrettyPrint(isPrettyPrint());
|
||||
myLastRequest = invocation.asHttpRequest(params);
|
||||
}
|
||||
|
||||
if (theIfVersionMatches != null) {
|
||||
|
@ -253,18 +260,17 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
new ResourceResponseHandler<>(theType, (Class<? extends IBaseResource>) null, id, allowHtmlResponse);
|
||||
|
||||
if (theNotModifiedHandler == null) {
|
||||
return invokeClient(
|
||||
myContext,
|
||||
binding,
|
||||
invocation,
|
||||
theEncoding,
|
||||
thePrettyPrint,
|
||||
myLogRequestAndResponse,
|
||||
theSummary,
|
||||
theSubsetElements,
|
||||
null,
|
||||
theCustomAcceptHeaderValue,
|
||||
theCustomHeaders);
|
||||
return invokeClient(new InvokeClientParameters<T>()
|
||||
.setContext(myContext)
|
||||
.setBinding(binding)
|
||||
.setClientInvocation(invocation)
|
||||
.setEncoding(theEncoding)
|
||||
.setPrettyPrint(thePrettyPrint)
|
||||
.setTheLogRequestAndResponse(myLogRequestAndResponse)
|
||||
.setSummaryMode(theSummary)
|
||||
.setSubsetElements(theSubsetElements)
|
||||
.setCustomAcceptHeader(theCustomAcceptHeaderValue)
|
||||
.setCustomHeaders(theCustomHeaders));
|
||||
}
|
||||
try {
|
||||
return invokeClient(
|
||||
|
@ -286,7 +292,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
|
||||
@Override
|
||||
public IFetchConformanceUntyped fetchConformance() {
|
||||
return new FetchConformanceInternal();
|
||||
return new FetchConformanceInternal(myClient);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -319,7 +325,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
|
||||
@Override
|
||||
public IHistory history() {
|
||||
return new HistoryInternal();
|
||||
return new HistoryInternal(myClient);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -340,27 +346,27 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
|
||||
@Override
|
||||
public IGetPage loadPage() {
|
||||
return new LoadPageInternal();
|
||||
return new LoadPageInternal(myClient);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IMeta meta() {
|
||||
return new MetaInternal();
|
||||
return new MetaInternal(myClient);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IOperation operation() {
|
||||
return new OperationInternal();
|
||||
return new OperationInternal(myClient);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPatch patch() {
|
||||
return new PatchInternal();
|
||||
return new PatchInternal(myClient);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IRead read() {
|
||||
return new ReadInternal();
|
||||
return new ReadInternal(myClient);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -395,7 +401,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
@Override
|
||||
public IUntypedQuery search() {
|
||||
return new SearchInternal();
|
||||
return new SearchInternal<>(myClient);
|
||||
}
|
||||
|
||||
private String toResourceName(Class<? extends IBaseResource> theType) {
|
||||
|
@ -404,12 +410,12 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
|
||||
@Override
|
||||
public ITransaction transaction() {
|
||||
return new TransactionInternal();
|
||||
return new TransactionInternal(myClient);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IUpdate update() {
|
||||
return new UpdateInternal();
|
||||
return new UpdateInternal(myClient);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -432,7 +438,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
|
||||
@Override
|
||||
public IValidate validate() {
|
||||
return new ValidateInternal();
|
||||
return new ValidateInternal(myClient);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -484,6 +490,12 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
private boolean myQueryLogRequestAndResponse;
|
||||
private Set<String> mySubsetElements;
|
||||
|
||||
private final IHttpClient myPreservedClient;
|
||||
|
||||
public BaseClientExecutable(IHttpClient theClient) {
|
||||
myPreservedClient = theClient;
|
||||
}
|
||||
|
||||
public String getCustomAcceptHeaderValue() {
|
||||
return myCustomAcceptHeaderValue;
|
||||
}
|
||||
|
@ -579,21 +591,27 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
IClientResponseHandler<Z> theHandler,
|
||||
BaseHttpClientInvocation theInvocation) {
|
||||
if (isKeepResponses()) {
|
||||
myLastRequest = theInvocation.asHttpRequest(getServerBase(), theParams, getEncoding(), myPrettyPrint);
|
||||
myLastRequest = theInvocation.asHttpRequest(new AsHttpRequestParams()
|
||||
.setUrlBase(getServerBase())
|
||||
.setClient(myClient)
|
||||
.setExtraParams(theParams)
|
||||
.setEncodingEnum(getParamEncoding())
|
||||
.setPrettyPrint(myPrettyPrint));
|
||||
}
|
||||
|
||||
Z resp = invokeClient(
|
||||
myContext,
|
||||
theHandler,
|
||||
theInvocation,
|
||||
myParamEncoding,
|
||||
myPrettyPrint,
|
||||
myQueryLogRequestAndResponse || myLogRequestAndResponse,
|
||||
mySummaryMode,
|
||||
mySubsetElements,
|
||||
myCacheControlDirective,
|
||||
myCustomAcceptHeaderValue,
|
||||
myCustomHeaderValues);
|
||||
InvokeClientParameters<Z> params = new InvokeClientParameters<Z>()
|
||||
.setContext(myContext)
|
||||
.setBinding(theHandler)
|
||||
.setClientInvocation(theInvocation)
|
||||
.setEncoding(myParamEncoding)
|
||||
.setPrettyPrint(myPrettyPrint)
|
||||
.setTheLogRequestAndResponse(myQueryLogRequestAndResponse || myLogRequestAndResponse)
|
||||
.setSummaryMode(mySummaryMode)
|
||||
.setSubsetElements(mySubsetElements)
|
||||
.setCacheControlDirective(myCacheControlDirective)
|
||||
.setCustomAcceptHeader(myCustomAcceptHeaderValue)
|
||||
.setCustomHeaders(myCustomHeaderValues);
|
||||
Z resp = invokeClient(params);
|
||||
return resp;
|
||||
}
|
||||
|
||||
|
@ -643,7 +661,11 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
EXEC extends IClientExecutable<?, OUTPUT>, QUERY extends IBaseQuery<QUERY>, OUTPUT>
|
||||
extends BaseClientExecutable<EXEC, OUTPUT> implements IBaseQuery<QUERY> {
|
||||
|
||||
private Map<String, List<String>> myParams = new LinkedHashMap<>();
|
||||
private final Map<String, List<String>> myParams = new LinkedHashMap<>();
|
||||
|
||||
public BaseSearch(IHttpClient theClient) {
|
||||
super(theClient);
|
||||
}
|
||||
|
||||
@Override
|
||||
public QUERY and(ICriterion<?> theCriterion) {
|
||||
|
@ -710,6 +732,10 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
private String myResourceBody;
|
||||
private String mySearchUrl;
|
||||
|
||||
public CreateInternal(IHttpClient theClient) {
|
||||
super(theClient);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICreateWithQuery conditional() {
|
||||
myConditional = true;
|
||||
|
@ -780,9 +806,12 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
private String mySearchUrl;
|
||||
private DeleteCascadeModeEnum myCascadeMode;
|
||||
|
||||
public DeleteInternal(IHttpClient theClient) {
|
||||
super(theClient);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodOutcome execute() {
|
||||
|
||||
Map<String, List<String>> additionalParams = new HashMap<>();
|
||||
if (myCascadeMode != null) {
|
||||
switch (myCascadeMode) {
|
||||
|
@ -888,6 +917,10 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
implements IFetchConformanceUntyped, IFetchConformanceTyped {
|
||||
private RuntimeResourceDefinition myType;
|
||||
|
||||
public FetchConformanceInternal(IHttpClient theClient) {
|
||||
super(theClient);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object execute() {
|
||||
ResourceResponseHandler binding = new ResourceResponseHandler(myType.getImplementingClass());
|
||||
|
@ -912,12 +945,13 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
private class GetPageInternal extends BaseClientExecutable<IGetPageTyped<Object>, Object>
|
||||
implements IGetPageTyped<Object> {
|
||||
|
||||
private Class<? extends IBaseBundle> myBundleType;
|
||||
private String myUrl;
|
||||
private final Class<? extends IBaseBundle> myBundleType;
|
||||
private final String myUrl;
|
||||
|
||||
private PagingHttpMethodEnum myPagingHttpMethod = PagingHttpMethodEnum.GET;
|
||||
|
||||
public GetPageInternal(String theUrl, Class<? extends IBaseBundle> theBundleType) {
|
||||
public GetPageInternal(IHttpClient theClient, String theUrl, Class<? extends IBaseBundle> theBundleType) {
|
||||
super(theClient);
|
||||
myUrl = theUrl;
|
||||
myBundleType = theBundleType;
|
||||
}
|
||||
|
@ -947,6 +981,10 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
private Class<? extends IBaseResource> myType;
|
||||
private DateRangeParam myAt;
|
||||
|
||||
public HistoryInternal(IHttpClient theClient) {
|
||||
super(theClient);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public IHistoryTyped andReturnBundle(Class theType) {
|
||||
|
@ -1056,10 +1094,16 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
private static final String PREVIOUS = "previous";
|
||||
private String myPageUrl;
|
||||
|
||||
private IHttpClient myClient;
|
||||
|
||||
public LoadPageInternal(IHttpClient theClient) {
|
||||
myClient = theClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends IBaseBundle> IGetPageTyped andReturnBundle(Class<T> theBundleType) {
|
||||
Validate.notNull(theBundleType, "theBundleType must not be null");
|
||||
return new GetPageInternal(myPageUrl, theBundleType);
|
||||
return new GetPageInternal(myClient, myPageUrl, theBundleType);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1129,6 +1173,10 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
private String myOnType;
|
||||
private MetaOperation myOperation;
|
||||
|
||||
public MetaInternal(IHttpClient theClient) {
|
||||
super(theClient);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IMetaAddOrDeleteUnsourced add() {
|
||||
myOperation = MetaOperation.ADD;
|
||||
|
@ -1303,6 +1351,10 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
private boolean myUseHttpGet;
|
||||
private boolean myReturnMethodOutcome;
|
||||
|
||||
public OperationInternal(IHttpClient theClient) {
|
||||
super(theClient);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void addParam(String theName, IBase theValue) {
|
||||
BaseRuntimeChildDefinition parameterChild = myParametersDef.getChildByName("parameter");
|
||||
|
@ -1716,6 +1768,10 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
private class PatchInternal extends BaseSearch<IPatchExecutable, IPatchWithQueryTyped, MethodOutcome>
|
||||
implements IPatch, IPatchWithBody, IPatchExecutable, IPatchWithQuery, IPatchWithQueryTyped {
|
||||
|
||||
public PatchInternal(IHttpClient theClient) {
|
||||
super(theClient);
|
||||
}
|
||||
|
||||
private boolean myConditional;
|
||||
private IIdType myId;
|
||||
private String myPatchBody;
|
||||
|
@ -1845,6 +1901,10 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
private ICallable myNotModifiedHandler;
|
||||
private RuntimeResourceDefinition myType;
|
||||
|
||||
public ReadInternal(IHttpClient theClient) {
|
||||
super(theClient);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object execute() { // AAA
|
||||
if (myId.hasVersionIdPart()) {
|
||||
|
@ -2038,7 +2098,8 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
private List<TokenParam> myTags = new ArrayList<>();
|
||||
private SearchTotalModeEnum myTotalMode;
|
||||
|
||||
public SearchInternal() {
|
||||
public SearchInternal(IHttpClient theClient) {
|
||||
super(theClient);
|
||||
myResourceType = null;
|
||||
myResourceName = null;
|
||||
mySearchUrl = null;
|
||||
|
@ -2097,7 +2158,6 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
|
||||
@Override
|
||||
public OUTPUT execute() {
|
||||
|
||||
Map<String, List<String>> params = getParamMap();
|
||||
|
||||
for (TokenParam next : myTags) {
|
||||
|
@ -2348,22 +2408,39 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
private EncodingEnum myRawBundleEncoding;
|
||||
private List<? extends IBaseResource> myResources;
|
||||
|
||||
public TransactionExecutable(IBaseBundle theBundle) {
|
||||
public TransactionExecutable(IHttpClient theClient, IBaseBundle theBundle) {
|
||||
this(theClient, null, theBundle, null);
|
||||
}
|
||||
|
||||
public TransactionExecutable(IHttpClient theClient, List<? extends IBaseResource> theResources) {
|
||||
this(theClient, null, null, theResources);
|
||||
}
|
||||
|
||||
public TransactionExecutable(IHttpClient theClient, String theStrBundle) {
|
||||
this(theClient, theStrBundle, null, null);
|
||||
}
|
||||
|
||||
public TransactionExecutable(
|
||||
IHttpClient theClient,
|
||||
String theStrBundle,
|
||||
IBaseBundle theBundle,
|
||||
List<? extends IBaseResource> theResources) {
|
||||
super(theClient);
|
||||
if (theBundle != null) {
|
||||
myBaseBundle = theBundle;
|
||||
}
|
||||
|
||||
public TransactionExecutable(List<? extends IBaseResource> theResources) {
|
||||
myResources = theResources;
|
||||
}
|
||||
|
||||
public TransactionExecutable(String theBundle) {
|
||||
myRawBundle = theBundle;
|
||||
if (theStrBundle != null) {
|
||||
myRawBundle = theStrBundle;
|
||||
myRawBundleEncoding = EncodingEnum.detectEncodingNoDefault(myRawBundle);
|
||||
if (myRawBundleEncoding == null) {
|
||||
throw new IllegalArgumentException(Msg.code(1395)
|
||||
+ myContext.getLocalizer().getMessage(GenericClient.class, "cantDetermineRequestType"));
|
||||
}
|
||||
}
|
||||
if (theResources != null) {
|
||||
myResources = theResources;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
@Override
|
||||
|
@ -2402,16 +2479,22 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
|
||||
private final class TransactionInternal implements ITransaction {
|
||||
|
||||
private IHttpClient myClient;
|
||||
|
||||
public TransactionInternal(IHttpClient theClient) {
|
||||
myClient = theClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITransactionTyped<String> withBundle(String theBundle) {
|
||||
Validate.notBlank(theBundle, "theBundle must not be null");
|
||||
return new TransactionExecutable<String>(theBundle);
|
||||
return new TransactionExecutable<String>(myClient, theBundle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends IBaseBundle> ITransactionTyped<T> withBundle(T theBundle) {
|
||||
Validate.notNull(theBundle, "theBundle must not be null");
|
||||
return new TransactionExecutable<T>(theBundle);
|
||||
return new TransactionExecutable<T>(myClient, theBundle);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -2432,7 +2515,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
}
|
||||
}
|
||||
|
||||
return new TransactionExecutable<>(theResources);
|
||||
return new TransactionExecutable<>(myClient, theResources);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2447,6 +2530,10 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
private String mySearchUrl;
|
||||
private boolean myIsHistoryRewrite;
|
||||
|
||||
public UpdateInternal(IHttpClient theClient) {
|
||||
super(theClient);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IUpdateTyped historyRewrite() {
|
||||
myIsHistoryRewrite = true;
|
||||
|
@ -2563,6 +2650,10 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
implements IValidate, IValidateUntyped {
|
||||
private IBaseResource myResource;
|
||||
|
||||
public ValidateInternal(IHttpClient theClient) {
|
||||
super(theClient);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodOutcome execute() {
|
||||
BaseHttpClientInvocation invocation =
|
||||
|
|
|
@ -24,12 +24,16 @@ import ca.uhn.fhir.context.FhirVersionEnum;
|
|||
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
import ca.uhn.fhir.parser.IParser;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.api.IVersionSpecificBundleFactory;
|
||||
import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
||||
import ca.uhn.fhir.rest.client.api.Header;
|
||||
import ca.uhn.fhir.rest.client.api.IHttpClient;
|
||||
import ca.uhn.fhir.rest.client.api.IHttpRequest;
|
||||
import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation;
|
||||
import ca.uhn.fhir.rest.client.model.AsHttpRequestParams;
|
||||
import ca.uhn.fhir.rest.param.HttpClientRequestParameters;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.hl7.fhir.instance.model.api.IBaseBinary;
|
||||
|
@ -106,6 +110,20 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
|
|||
EncodingEnum theEncoding,
|
||||
Boolean thePrettyPrint)
|
||||
throws DataFormatException {
|
||||
return asHttpRequest(new AsHttpRequestParams()
|
||||
.setUrlBase(theUrlBase)
|
||||
.setExtraParams(theExtraParams)
|
||||
.setEncodingEnum(theEncoding)
|
||||
.setPrettyPrint(thePrettyPrint));
|
||||
}
|
||||
|
||||
@Override
|
||||
public IHttpRequest asHttpRequest(AsHttpRequestParams theParams) {
|
||||
String theUrlBase = theParams.getUrlBase();
|
||||
Map<String, List<String>> theExtraParams = theParams.getExtraParams();
|
||||
EncodingEnum theEncoding = theParams.getEncodingEnum();
|
||||
Boolean thePrettyPrint = theParams.getPrettyPrint();
|
||||
|
||||
StringBuilder url = new StringBuilder();
|
||||
|
||||
if (myUrlPath == null) {
|
||||
|
@ -121,8 +139,18 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
|
|||
}
|
||||
|
||||
appendExtraParamsWithQuestionMark(theExtraParams, url, url.indexOf("?") == -1);
|
||||
IHttpClient httpClient = getRestfulClientFactory()
|
||||
IHttpClient httpClient;
|
||||
if (theParams.getClient() != null) {
|
||||
// use the provided one
|
||||
httpClient = theParams.getClient();
|
||||
// update the url to the one we want (in case the
|
||||
// previous client did not have the correct one
|
||||
httpClient.setNewUrl(url, myIfNoneExistString, myIfNoneExistParams);
|
||||
} else {
|
||||
// make a new one
|
||||
httpClient = getRestfulClientFactory()
|
||||
.getHttpClient(url, myIfNoneExistParams, myIfNoneExistString, getRequestType(), getHeaders());
|
||||
}
|
||||
|
||||
if (myResource != null && IBaseBinary.class.isAssignableFrom(myResource.getClass())) {
|
||||
IBaseBinary binary = (IBaseBinary) myResource;
|
||||
|
@ -140,12 +168,25 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
|
|||
}
|
||||
|
||||
if (myParams != null) {
|
||||
return httpClient.createParamRequest(getContext(), myParams, encoding);
|
||||
IHttpRequest request = httpClient.createParamRequest(getContext(), myParams, encoding);
|
||||
return request;
|
||||
}
|
||||
encoding = ObjectUtils.defaultIfNull(encoding, EncodingEnum.JSON);
|
||||
String contents = encodeContents(thePrettyPrint, encoding);
|
||||
String contentType = getContentType(encoding);
|
||||
return httpClient.createByteRequest(getContext(), contents, contentType, encoding);
|
||||
HttpClientRequestParameters parameters = new HttpClientRequestParameters(url.toString(), getRequestType());
|
||||
parameters.setContents(contents);
|
||||
parameters.setContentType(contentType);
|
||||
parameters.setFhirContext(getContext());
|
||||
parameters.setEncodingEnum(encoding);
|
||||
parameters.setRequestTypeEnum(getRequestType());
|
||||
IHttpRequest request = httpClient.createRequest(parameters);
|
||||
for (Header header : getHeaders()) {
|
||||
request.addHeader(header.getName(), header.getValue());
|
||||
}
|
||||
httpClient.addHeadersToRequest(request, encoding, parameters.getFhirContext());
|
||||
request.addHeader(Constants.HEADER_CONTENT_TYPE, contentType + Constants.HEADER_SUFFIX_CT_UTF_8);
|
||||
return request;
|
||||
}
|
||||
|
||||
private String getContentType(EncodingEnum encoding) {
|
||||
|
|
|
@ -24,6 +24,8 @@ import ca.uhn.fhir.rest.api.EncodingEnum;
|
|||
import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
||||
import ca.uhn.fhir.rest.client.api.IHttpRequest;
|
||||
import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation;
|
||||
import ca.uhn.fhir.rest.client.model.AsHttpRequestParams;
|
||||
import ca.uhn.fhir.rest.client.model.CreateRequestParameters;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
|
||||
import java.util.List;
|
||||
|
@ -31,8 +33,8 @@ import java.util.Map;
|
|||
|
||||
public class HttpDeleteClientInvocation extends BaseHttpClientInvocation {
|
||||
|
||||
private String myUrlPath;
|
||||
private Map<String, List<String>> myParams;
|
||||
private final String myUrlPath;
|
||||
private final Map<String, List<String>> myParams;
|
||||
|
||||
public HttpDeleteClientInvocation(
|
||||
FhirContext theContext, IIdType theId, Map<String, List<String>> theAdditionalParams) {
|
||||
|
@ -54,6 +56,20 @@ public class HttpDeleteClientInvocation extends BaseHttpClientInvocation {
|
|||
Map<String, List<String>> theExtraParams,
|
||||
EncodingEnum theEncoding,
|
||||
Boolean thePrettyPrint) {
|
||||
return asHttpRequest(new AsHttpRequestParams()
|
||||
.setUrlBase(theUrlBase)
|
||||
.setExtraParams(theExtraParams)
|
||||
.setEncodingEnum(theEncoding)
|
||||
.setPrettyPrint(thePrettyPrint));
|
||||
}
|
||||
|
||||
@Override
|
||||
public IHttpRequest asHttpRequest(AsHttpRequestParams theParams) {
|
||||
String theUrlBase = theParams.getUrlBase();
|
||||
Map<String, List<String>> theExtraParams = theParams.getExtraParams();
|
||||
EncodingEnum theEncoding = theParams.getEncodingEnum();
|
||||
Boolean thePrettyPrint = theParams.getPrettyPrint();
|
||||
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append(theUrlBase);
|
||||
if (!theUrlBase.endsWith("/")) {
|
||||
|
@ -64,6 +80,11 @@ public class HttpDeleteClientInvocation extends BaseHttpClientInvocation {
|
|||
appendExtraParamsWithQuestionMark(myParams, b, b.indexOf("?") == -1);
|
||||
appendExtraParamsWithQuestionMark(theExtraParams, b, b.indexOf("?") == -1);
|
||||
|
||||
return createHttpRequest(b.toString(), theEncoding, RequestTypeEnum.DELETE);
|
||||
CreateRequestParameters requestParameters = new CreateRequestParameters();
|
||||
requestParameters.setClient(theParams.getClient());
|
||||
requestParameters.setRequestTypeEnum(RequestTypeEnum.DELETE);
|
||||
requestParameters.setEncodingEnum(theEncoding);
|
||||
requestParameters.setUrl(b.toString());
|
||||
return createHttpRequest(requestParameters);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,8 @@ import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
|||
import ca.uhn.fhir.rest.client.api.IHttpRequest;
|
||||
import ca.uhn.fhir.rest.client.api.UrlSourceEnum;
|
||||
import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation;
|
||||
import ca.uhn.fhir.rest.client.model.AsHttpRequestParams;
|
||||
import ca.uhn.fhir.rest.client.model.CreateRequestParameters;
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
|
@ -87,6 +89,18 @@ public class HttpGetClientInvocation extends BaseHttpClientInvocation {
|
|||
Map<String, List<String>> theExtraParams,
|
||||
EncodingEnum theEncoding,
|
||||
Boolean thePrettyPrint) {
|
||||
return asHttpRequest(new AsHttpRequestParams()
|
||||
.setUrlBase(theUrlBase)
|
||||
.setExtraParams(theExtraParams)
|
||||
.setPrettyPrint(thePrettyPrint)
|
||||
.setEncodingEnum(theEncoding));
|
||||
}
|
||||
|
||||
@Override
|
||||
public IHttpRequest asHttpRequest(AsHttpRequestParams theAsHttpRequestParams) {
|
||||
String theUrlBase = theAsHttpRequestParams.getUrlBase();
|
||||
Map<String, List<String>> theExtraParams = theAsHttpRequestParams.getExtraParams();
|
||||
EncodingEnum theEncoding = theAsHttpRequestParams.getEncodingEnum();
|
||||
StringBuilder b = new StringBuilder();
|
||||
|
||||
if (!myUrlPath.contains("://")) {
|
||||
|
@ -110,7 +124,12 @@ public class HttpGetClientInvocation extends BaseHttpClientInvocation {
|
|||
|
||||
appendExtraParamsWithQuestionMark(theExtraParams, b, first);
|
||||
|
||||
IHttpRequest retVal = super.createHttpRequest(b.toString(), theEncoding, RequestTypeEnum.GET);
|
||||
CreateRequestParameters createRequestParameters = new CreateRequestParameters()
|
||||
.setRequestTypeEnum(RequestTypeEnum.GET)
|
||||
.setEncodingEnum(theEncoding)
|
||||
.setUrl(b.toString())
|
||||
.setClient(theAsHttpRequestParams.getClient());
|
||||
IHttpRequest retVal = super.createHttpRequest(createRequestParameters);
|
||||
retVal.setUrlSource(myUrlSource);
|
||||
|
||||
return retVal;
|
||||
|
|
|
@ -20,11 +20,16 @@
|
|||
package ca.uhn.fhir.rest.client.method;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
||||
import ca.uhn.fhir.rest.client.api.Header;
|
||||
import ca.uhn.fhir.rest.client.api.IHttpClient;
|
||||
import ca.uhn.fhir.rest.client.api.IHttpRequest;
|
||||
import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation;
|
||||
import ca.uhn.fhir.rest.client.model.AsHttpRequestParams;
|
||||
import ca.uhn.fhir.rest.client.model.CreateRequestParameters;
|
||||
import ca.uhn.fhir.rest.param.HttpClientRequestParameters;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
|
||||
import java.util.List;
|
||||
|
@ -32,10 +37,10 @@ import java.util.Map;
|
|||
|
||||
public class HttpPatchClientInvocation extends BaseHttpClientInvocation {
|
||||
|
||||
private String myUrlPath;
|
||||
private final String myUrlPath;
|
||||
private Map<String, List<String>> myParams;
|
||||
private String myContents;
|
||||
private String myContentType;
|
||||
private final String myContents;
|
||||
private final String myContentType;
|
||||
|
||||
public HttpPatchClientInvocation(FhirContext theContext, IIdType theId, String theContentType, String theContents) {
|
||||
super(theContext);
|
||||
|
@ -58,6 +63,20 @@ public class HttpPatchClientInvocation extends BaseHttpClientInvocation {
|
|||
Map<String, List<String>> theExtraParams,
|
||||
EncodingEnum theEncoding,
|
||||
Boolean thePrettyPrint) {
|
||||
return asHttpRequest(new AsHttpRequestParams()
|
||||
.setUrlBase(theUrlBase)
|
||||
.setExtraParams(theExtraParams)
|
||||
.setEncodingEnum(theEncoding)
|
||||
.setPrettyPrint(thePrettyPrint));
|
||||
}
|
||||
|
||||
@Override
|
||||
public IHttpRequest asHttpRequest(AsHttpRequestParams theParams) {
|
||||
String theUrlBase = theParams.getUrlBase();
|
||||
Map<String, List<String>> theExtraParams = theParams.getExtraParams();
|
||||
EncodingEnum theEncoding = theParams.getEncodingEnum();
|
||||
Boolean thePrettyPrint = theParams.getPrettyPrint();
|
||||
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append(theUrlBase);
|
||||
if (!theUrlBase.endsWith("/")) {
|
||||
|
@ -68,7 +87,12 @@ public class HttpPatchClientInvocation extends BaseHttpClientInvocation {
|
|||
appendExtraParamsWithQuestionMark(myParams, b, b.indexOf("?") == -1);
|
||||
appendExtraParamsWithQuestionMark(theExtraParams, b, b.indexOf("?") == -1);
|
||||
|
||||
return createHttpRequest(b.toString(), theEncoding, RequestTypeEnum.PATCH);
|
||||
CreateRequestParameters requestParameters = new CreateRequestParameters();
|
||||
requestParameters.setClient(theParams.getClient());
|
||||
requestParameters.setUrl(b.toString());
|
||||
requestParameters.setEncodingEnum(theEncoding);
|
||||
requestParameters.setRequestTypeEnum(RequestTypeEnum.PATCH);
|
||||
return createHttpRequest(requestParameters);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -77,4 +101,34 @@ public class HttpPatchClientInvocation extends BaseHttpClientInvocation {
|
|||
.getHttpClient(new StringBuilder(theUrl), null, null, theRequestType, getHeaders());
|
||||
return httpClient.createByteRequest(getContext(), myContents, myContentType, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IHttpRequest createHttpRequest(CreateRequestParameters theParameters) {
|
||||
IHttpClient client;
|
||||
if (theParameters.getClient() == null) {
|
||||
client = getRestfulClientFactory()
|
||||
.getHttpClient(
|
||||
new StringBuilder(theParameters.getUrl()),
|
||||
null,
|
||||
null,
|
||||
theParameters.getRequestTypeEnum(),
|
||||
getHeaders());
|
||||
} else {
|
||||
client = theParameters.getClient();
|
||||
client.setNewUrl(new StringBuilder(theParameters.getUrl()), null, null);
|
||||
}
|
||||
|
||||
HttpClientRequestParameters params =
|
||||
new HttpClientRequestParameters(theParameters.getUrl(), RequestTypeEnum.PATCH);
|
||||
params.setContents(myContents);
|
||||
params.setContentType(myContentType);
|
||||
params.setFhirContext(getContext());
|
||||
IHttpRequest req = client.createRequest(params);
|
||||
for (Header h : getHeaders()) {
|
||||
req.addHeader(h.getName(), h.getValue());
|
||||
}
|
||||
client.addHeadersToRequest(req, theParameters.getEncodingEnum(), getContext());
|
||||
req.addHeader(Constants.HEADER_CONTENT_TYPE, params.getContentType() + Constants.HEADER_SUFFIX_CT_UTF_8);
|
||||
return req;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,8 @@ import ca.uhn.fhir.rest.api.PagingHttpMethodEnum;
|
|||
import ca.uhn.fhir.rest.client.api.IHttpRequest;
|
||||
import ca.uhn.fhir.rest.client.api.UrlSourceEnum;
|
||||
import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation;
|
||||
import ca.uhn.fhir.rest.client.model.AsHttpRequestParams;
|
||||
import ca.uhn.fhir.rest.client.model.CreateRequestParameters;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -34,7 +36,7 @@ public class HttpSimpleClientInvocation extends BaseHttpClientInvocation {
|
|||
private final String myUrl;
|
||||
private UrlSourceEnum myUrlSource = UrlSourceEnum.EXPLICIT;
|
||||
|
||||
private PagingHttpMethodEnum myPagingHttpMethod;
|
||||
private final PagingHttpMethodEnum myPagingHttpMethod;
|
||||
|
||||
public HttpSimpleClientInvocation(
|
||||
FhirContext theContext, String theUrlPath, PagingHttpMethodEnum thePagingHttpMethod) {
|
||||
|
@ -49,9 +51,23 @@ public class HttpSimpleClientInvocation extends BaseHttpClientInvocation {
|
|||
Map<String, List<String>> theExtraParams,
|
||||
EncodingEnum theEncoding,
|
||||
Boolean thePrettyPrint) {
|
||||
IHttpRequest retVal = createHttpRequest(myUrl, theEncoding, myPagingHttpMethod.getRequestType());
|
||||
retVal.setUrlSource(myUrlSource);
|
||||
return retVal;
|
||||
return asHttpRequest(new AsHttpRequestParams()
|
||||
.setUrlBase(myUrl)
|
||||
.setExtraParams(theExtraParams)
|
||||
.setEncodingEnum(theEncoding)
|
||||
.setPrettyPrint(thePrettyPrint));
|
||||
}
|
||||
|
||||
@Override
|
||||
public IHttpRequest asHttpRequest(AsHttpRequestParams theParams) {
|
||||
CreateRequestParameters parameters = new CreateRequestParameters();
|
||||
parameters.setUrl(myUrl);
|
||||
parameters.setEncodingEnum(theParams.getEncodingEnum());
|
||||
parameters.setRequestTypeEnum(myPagingHttpMethod.getRequestType());
|
||||
parameters.setClient(theParams.getClient());
|
||||
IHttpRequest request = createHttpRequest(parameters);
|
||||
request.setUrlSource(myUrlSource);
|
||||
return request;
|
||||
}
|
||||
|
||||
public void setUrlSource(UrlSourceEnum theUrlSource) {
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR - Client Framework
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2024 Smile CDR, Inc.
|
||||
* %%
|
||||
* 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%
|
||||
*/
|
||||
package ca.uhn.fhir.rest.client.model;
|
||||
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.client.api.IHttpClient;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class AsHttpRequestParams {
|
||||
/**
|
||||
* The URL for the request
|
||||
*/
|
||||
private String myUrlBase;
|
||||
|
||||
/**
|
||||
* Extra parameters
|
||||
*/
|
||||
private Map<String, List<String>> myExtraParams;
|
||||
|
||||
/**
|
||||
* Encoding to use (JSON, fhir+json, etc)
|
||||
*/
|
||||
private EncodingEnum myEncodingEnum;
|
||||
|
||||
/**
|
||||
* Whether logs should print pretty or not (for request parsing only)
|
||||
*/
|
||||
private Boolean myPrettyPrint;
|
||||
|
||||
/**
|
||||
* The client to use for this request
|
||||
*/
|
||||
private IHttpClient myClient;
|
||||
|
||||
public String getUrlBase() {
|
||||
return myUrlBase;
|
||||
}
|
||||
|
||||
public AsHttpRequestParams setUrlBase(String theUrlBase) {
|
||||
myUrlBase = theUrlBase;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Map<String, List<String>> getExtraParams() {
|
||||
if (myExtraParams == null) {
|
||||
myExtraParams = new HashMap<>();
|
||||
}
|
||||
return myExtraParams;
|
||||
}
|
||||
|
||||
public void addExtraParam(String theKey, String theValue) {
|
||||
Map<String, List<String>> extraParams = getExtraParams();
|
||||
if (!extraParams.containsKey(theKey)) {
|
||||
extraParams.put(theKey, new ArrayList<>());
|
||||
}
|
||||
extraParams.get(theKey).add(theValue);
|
||||
}
|
||||
|
||||
public AsHttpRequestParams setExtraParams(Map<String, List<String>> theExtraParams) {
|
||||
myExtraParams = theExtraParams;
|
||||
return this;
|
||||
}
|
||||
|
||||
public EncodingEnum getEncodingEnum() {
|
||||
return myEncodingEnum;
|
||||
}
|
||||
|
||||
public AsHttpRequestParams setEncodingEnum(EncodingEnum theEncodingEnum) {
|
||||
myEncodingEnum = theEncodingEnum;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Boolean getPrettyPrint() {
|
||||
return myPrettyPrint;
|
||||
}
|
||||
|
||||
public AsHttpRequestParams setPrettyPrint(Boolean thePrettyPrint) {
|
||||
myPrettyPrint = thePrettyPrint;
|
||||
return this;
|
||||
}
|
||||
|
||||
public IHttpClient getClient() {
|
||||
return myClient;
|
||||
}
|
||||
|
||||
public AsHttpRequestParams setClient(IHttpClient theClient) {
|
||||
myClient = theClient;
|
||||
return this;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR - Client Framework
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2024 Smile CDR, Inc.
|
||||
* %%
|
||||
* 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%
|
||||
*/
|
||||
package ca.uhn.fhir.rest.client.model;
|
||||
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
||||
import ca.uhn.fhir.rest.client.api.IHttpClient;
|
||||
|
||||
public class CreateRequestParameters {
|
||||
|
||||
/**
|
||||
* The complete FHIR url to which the http request will be sent
|
||||
*/
|
||||
private String myUrl;
|
||||
/**
|
||||
* The encoding to use for any serialized content sent to the
|
||||
* server
|
||||
*/
|
||||
private EncodingEnum myEncodingEnum;
|
||||
/**
|
||||
* the type of HTTP request (GET, DELETE, ..)
|
||||
*/
|
||||
private RequestTypeEnum myRequestTypeEnum;
|
||||
|
||||
private IHttpClient myClient;
|
||||
|
||||
public String getUrl() {
|
||||
return myUrl;
|
||||
}
|
||||
|
||||
public CreateRequestParameters setUrl(String theUrl) {
|
||||
myUrl = theUrl;
|
||||
return this;
|
||||
}
|
||||
|
||||
public EncodingEnum getEncodingEnum() {
|
||||
return myEncodingEnum;
|
||||
}
|
||||
|
||||
public CreateRequestParameters setEncodingEnum(EncodingEnum theEncodingEnum) {
|
||||
myEncodingEnum = theEncodingEnum;
|
||||
return this;
|
||||
}
|
||||
|
||||
public RequestTypeEnum getRequestTypeEnum() {
|
||||
return myRequestTypeEnum;
|
||||
}
|
||||
|
||||
public CreateRequestParameters setRequestTypeEnum(RequestTypeEnum theRequestTypeEnum) {
|
||||
myRequestTypeEnum = theRequestTypeEnum;
|
||||
return this;
|
||||
}
|
||||
|
||||
public IHttpClient getClient() {
|
||||
return myClient;
|
||||
}
|
||||
|
||||
public CreateRequestParameters setClient(IHttpClient theClient) {
|
||||
myClient = theClient;
|
||||
return this;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,165 @@
|
|||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR - Client Framework
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2024 Smile CDR, Inc.
|
||||
* %%
|
||||
* 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%
|
||||
*/
|
||||
package ca.uhn.fhir.rest.client.model;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.api.CacheControlDirective;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.api.SummaryEnum;
|
||||
import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation;
|
||||
import ca.uhn.fhir.rest.client.method.IClientResponseHandler;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class InvokeClientParameters<T> {
|
||||
private FhirContext myContext;
|
||||
private IClientResponseHandler<T> myBinding;
|
||||
private BaseHttpClientInvocation myClientInvocation;
|
||||
private EncodingEnum myEncoding;
|
||||
private Boolean myPrettyPrint;
|
||||
private boolean theLogRequestAndResponse;
|
||||
private SummaryEnum mySummaryMode;
|
||||
private Set<String> mySubsetElements;
|
||||
private CacheControlDirective myCacheControlDirective;
|
||||
private String myCustomAcceptHeader;
|
||||
private Map<String, List<String>> myCustomHeaders;
|
||||
|
||||
public FhirContext getContext() {
|
||||
return myContext;
|
||||
}
|
||||
|
||||
public InvokeClientParameters<T> setContext(FhirContext theContext) {
|
||||
myContext = theContext;
|
||||
return this;
|
||||
}
|
||||
|
||||
public IClientResponseHandler<T> getBinding() {
|
||||
return myBinding;
|
||||
}
|
||||
|
||||
public InvokeClientParameters<T> setBinding(IClientResponseHandler<T> theBinding) {
|
||||
myBinding = theBinding;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BaseHttpClientInvocation getClientInvocation() {
|
||||
return myClientInvocation;
|
||||
}
|
||||
|
||||
public InvokeClientParameters<T> setClientInvocation(BaseHttpClientInvocation theClientInvocation) {
|
||||
myClientInvocation = theClientInvocation;
|
||||
return this;
|
||||
}
|
||||
|
||||
public EncodingEnum getEncoding() {
|
||||
return myEncoding;
|
||||
}
|
||||
|
||||
public InvokeClientParameters<T> setEncoding(EncodingEnum theEncoding) {
|
||||
myEncoding = theEncoding;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Boolean getPrettyPrint() {
|
||||
return myPrettyPrint;
|
||||
}
|
||||
|
||||
public InvokeClientParameters<T> setPrettyPrint(Boolean thePrettyPrint) {
|
||||
myPrettyPrint = thePrettyPrint;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isTheLogRequestAndResponse() {
|
||||
return theLogRequestAndResponse;
|
||||
}
|
||||
|
||||
public InvokeClientParameters<T> setTheLogRequestAndResponse(boolean theTheLogRequestAndResponse) {
|
||||
theLogRequestAndResponse = theTheLogRequestAndResponse;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SummaryEnum getSummaryMode() {
|
||||
return mySummaryMode;
|
||||
}
|
||||
|
||||
public InvokeClientParameters<T> setSummaryMode(SummaryEnum theSummaryMode) {
|
||||
mySummaryMode = theSummaryMode;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Set<String> getSubsetElements() {
|
||||
if (mySubsetElements == null) {
|
||||
mySubsetElements = new HashSet<>();
|
||||
}
|
||||
return mySubsetElements;
|
||||
}
|
||||
|
||||
public InvokeClientParameters<T> setSubsetElements(Set<String> theSubsetElements) {
|
||||
mySubsetElements = theSubsetElements;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void addSubsetElements(String theEl) {
|
||||
getSubsetElements().add(theEl);
|
||||
}
|
||||
|
||||
public CacheControlDirective getCacheControlDirective() {
|
||||
return myCacheControlDirective;
|
||||
}
|
||||
|
||||
public InvokeClientParameters<T> setCacheControlDirective(CacheControlDirective theCacheControlDirective) {
|
||||
myCacheControlDirective = theCacheControlDirective;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getCustomAcceptHeader() {
|
||||
return myCustomAcceptHeader;
|
||||
}
|
||||
|
||||
public InvokeClientParameters<T> setCustomAcceptHeader(String theCustomAcceptHeader) {
|
||||
myCustomAcceptHeader = theCustomAcceptHeader;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Map<String, List<String>> getCustomHeaders() {
|
||||
if (myCustomHeaders == null) {
|
||||
myCustomHeaders = new HashMap<>();
|
||||
}
|
||||
return myCustomHeaders;
|
||||
}
|
||||
|
||||
public InvokeClientParameters<T> setCustomHeaders(Map<String, List<String>> theCustomHeaders) {
|
||||
myCustomHeaders = theCustomHeaders;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void addCustomHeader(String theKey, String theValue) {
|
||||
Map<String, List<String>> headers = getCustomHeaders();
|
||||
if (!headers.containsKey(theKey)) {
|
||||
headers.put(theKey, new ArrayList<>());
|
||||
}
|
||||
headers.get(theKey).add(theValue);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
type: fix
|
||||
issue: 6180
|
||||
title: "Fixed GenericClient so that the IHttpClient (and settings used
|
||||
to create it) are preserved for the lifetime of the client.
|
||||
"
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
type: change
|
||||
issue: 6261
|
||||
title: "Upgrading to Jakarta had caused a problem with the version of java-simple-mail that was in use. This has been updated to be conformant
|
||||
with the Jakarta Mail APIs. Thanks to Thomas Papke(@thopap) for the contribution!"
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
type: fix
|
||||
issue: 6317
|
||||
title: "Previously, defining a unique combo Search Parameter with the DateTime component and submitting multiple
|
||||
resources with the same dateTime element (e.g. Observation.effectiveDateTime) resulted in duplicate resource creation.
|
||||
This has been fixed."
|
||||
|
|
@ -29,6 +29,7 @@ import ca.uhn.fhir.rest.client.api.IHttpClient;
|
|||
import ca.uhn.fhir.rest.client.api.IHttpRequest;
|
||||
import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation;
|
||||
import ca.uhn.fhir.rest.client.method.MethodUtil;
|
||||
import ca.uhn.fhir.rest.param.HttpClientRequestParameters;
|
||||
import jakarta.ws.rs.client.Client;
|
||||
import jakarta.ws.rs.client.Entity;
|
||||
import jakarta.ws.rs.client.Invocation.Builder;
|
||||
|
@ -37,9 +38,12 @@ import jakarta.ws.rs.core.MultivaluedHashMap;
|
|||
import jakarta.ws.rs.core.MultivaluedMap;
|
||||
import org.hl7.fhir.instance.model.api.IBaseBinary;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
/**
|
||||
* A Http Request based on JaxRs. This is an adapter around the class
|
||||
* {@link jakarta.ws.rs.client.Client Client}
|
||||
|
@ -83,7 +87,15 @@ public class JaxRsHttpClient implements IHttpClient {
|
|||
@Override
|
||||
public IHttpRequest createParamRequest(
|
||||
FhirContext theContext, Map<String, List<String>> theParams, EncodingEnum theEncoding) {
|
||||
MultivaluedMap<String, String> map = new MultivaluedHashMap<String, String>();
|
||||
Entity<Form> entity = getFormEntity(theParams);
|
||||
myRequestType = RequestTypeEnum.POST;
|
||||
JaxRsHttpRequest retVal = createHttpRequest(entity);
|
||||
addHeadersToRequest(retVal, theEncoding, theContext);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private static Entity<Form> getFormEntity(Map<String, List<String>> theParams) {
|
||||
MultivaluedMap<String, String> map = new MultivaluedHashMap<>();
|
||||
for (Map.Entry<String, List<String>> nextParam : theParams.entrySet()) {
|
||||
List<String> value = nextParam.getValue();
|
||||
for (String s : value) {
|
||||
|
@ -91,9 +103,7 @@ public class JaxRsHttpClient implements IHttpClient {
|
|||
}
|
||||
}
|
||||
Entity<Form> entity = Entity.form(map);
|
||||
JaxRsHttpRequest retVal = createHttpRequest(entity);
|
||||
addHeadersToRequest(retVal, theEncoding, theContext);
|
||||
return retVal;
|
||||
return entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -111,6 +121,60 @@ public class JaxRsHttpClient implements IHttpClient {
|
|||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IHttpRequest createRequest(HttpClientRequestParameters theParameters) {
|
||||
Map<String, String> additionalHeaders = new HashMap<>();
|
||||
Entity<?> entity;
|
||||
myRequestType = theParameters.getRequestTypeEnum();
|
||||
switch (theParameters.getRequestTypeEnum()) {
|
||||
case POST:
|
||||
case PUT:
|
||||
if (theParameters.getBaseBinary() != null) {
|
||||
entity = Entity.entity(
|
||||
theParameters.getBaseBinary().getContentAsBase64(),
|
||||
theParameters.getBaseBinary().getContentType());
|
||||
} else if (theParameters.getByteContents() != null) {
|
||||
entity = Entity.entity(
|
||||
theParameters.getByteContents(),
|
||||
theParameters.getContentType() + Constants.HEADER_SUFFIX_CT_UTF_8);
|
||||
additionalHeaders.put(
|
||||
Constants.HEADER_CONTENT_TYPE,
|
||||
theParameters.getContentType() + Constants.HEADER_SUFFIX_CT_UTF_8);
|
||||
} else if (isNotBlank(theParameters.getContents())) {
|
||||
entity = Entity.entity(
|
||||
theParameters.getContents(),
|
||||
theParameters.getContentType() + Constants.HEADER_SUFFIX_CT_UTF_8);
|
||||
additionalHeaders.put(
|
||||
Constants.HEADER_CONTENT_TYPE,
|
||||
theParameters.getContentType() + Constants.HEADER_SUFFIX_CT_UTF_8);
|
||||
} else {
|
||||
entity = getFormEntity(theParameters.getFormParams());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
entity = null;
|
||||
}
|
||||
JaxRsHttpRequest request = createHttpRequest(entity);
|
||||
for (Map.Entry<String, String> entrySet : additionalHeaders.entrySet()) {
|
||||
request.addHeader(entrySet.getKey(), entrySet.getValue());
|
||||
}
|
||||
addHeadersToRequest(request, theParameters.getEncodingEnum(), theParameters.getFhirContext());
|
||||
return request;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addHeadersToRequest(IHttpRequest theRequest, EncodingEnum theEncodingEnum, FhirContext theContext) {
|
||||
// nothing to do for this client
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNewUrl(
|
||||
StringBuilder theUrl, String theIfNoneExistString, Map<String, List<String>> theIfNoneExistParams) {
|
||||
myUrl = theUrl;
|
||||
myIfNoneExistString = theIfNoneExistString;
|
||||
myIfNoneExistParams = theIfNoneExistParams;
|
||||
}
|
||||
|
||||
public void addHeadersToRequest(JaxRsHttpRequest theHttpRequest, EncodingEnum theEncoding, FhirContext theContext) {
|
||||
if (myHeaders != null) {
|
||||
for (Header next : myHeaders) {
|
||||
|
|
|
@ -75,7 +75,6 @@ public class GenericJaxRsClientDstu2Test {
|
|||
}
|
||||
|
||||
private String getPatientFeedWithOneResult() {
|
||||
|
||||
String msg = "<Bundle xmlns=\"http://hl7.org/fhir\">\n" +
|
||||
"<id>d039f91a-cc3c-4013-988e-af4d8d0614bd</id>\n" +
|
||||
"<entry>\n" +
|
||||
|
@ -108,24 +107,20 @@ public class GenericJaxRsClientDstu2Test {
|
|||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient(ourServer.getBaseUrl() + "/fhir");
|
||||
|
||||
|
||||
client.fetchConformance().ofType(Conformance.class).execute();
|
||||
assertEquals(ourServer.getBaseUrl() + "/fhir/metadata", CAPTURE_SERVLET.ourRequestUri);
|
||||
assertThat(CAPTURE_SERVLET.ourRequestHeaders.get("Accept")).hasSize(1);
|
||||
assertThat(CAPTURE_SERVLET.ourRequestHeaders.get("Accept").get(0).getValue()).contains(Constants.HEADER_ACCEPT_VALUE_XML_OR_JSON_LEGACY);
|
||||
|
||||
|
||||
client.fetchConformance().ofType(Conformance.class).encodedJson().execute();
|
||||
assertEquals(ourServer.getBaseUrl() + "/fhir/metadata?_format=json", CAPTURE_SERVLET.ourRequestUri);
|
||||
assertThat(CAPTURE_SERVLET.ourRequestHeaders.get("Accept")).hasSize(1);
|
||||
assertThat(CAPTURE_SERVLET.ourRequestHeaders.get("Accept").get(0).getValue()).contains(Constants.CT_FHIR_JSON);
|
||||
|
||||
|
||||
client.fetchConformance().ofType(Conformance.class).encodedXml().execute();
|
||||
assertEquals(ourServer.getBaseUrl() + "/fhir/metadata?_format=xml", CAPTURE_SERVLET.ourRequestUri);
|
||||
assertThat(CAPTURE_SERVLET.ourRequestHeaders.get("Accept")).hasSize(1);
|
||||
assertThat(CAPTURE_SERVLET.ourRequestHeaders.get("Accept").get(0).getValue()).contains(Constants.CT_FHIR_XML);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -888,7 +883,6 @@ public class GenericJaxRsClientDstu2Test {
|
|||
.withParameter(Parameters.class, "name1", weirdBase)
|
||||
.execute();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -900,13 +894,11 @@ public class GenericJaxRsClientDstu2Test {
|
|||
outParams.addParameter().setValue(new StringDt("STRINGVALOUT2"));
|
||||
final String respString = p.encodeResourceToString(outParams);
|
||||
|
||||
|
||||
CAPTURE_SERVLET.ourResponseContentType = Constants.CT_FHIR_XML + "; charset=UTF-8";
|
||||
CAPTURE_SERVLET.ourResponseBody = respString;
|
||||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient(ourServer.getBaseUrl() + "/fhir");
|
||||
|
||||
|
||||
client
|
||||
.operation()
|
||||
.onInstance(new IdDt("http://foo/Patient/1"))
|
||||
|
@ -916,10 +908,8 @@ public class GenericJaxRsClientDstu2Test {
|
|||
.useHttpGet()
|
||||
.execute();
|
||||
|
||||
|
||||
assertEquals(ourServer.getBaseUrl() + "/fhir/Patient/1/$validate-code?code=8495-4&system=http%3A%2F%2Floinc.org", CAPTURE_SERVLET.ourRequestUri);
|
||||
|
||||
|
||||
client
|
||||
.operation()
|
||||
.onInstance(new IdDt("http://foo/Patient/1"))
|
||||
|
@ -927,7 +917,6 @@ public class GenericJaxRsClientDstu2Test {
|
|||
.withParameter(Parameters.class, "code", new CodeDt("8495-4"))
|
||||
.andParameter("system", new UriDt("http://loinc.org"))
|
||||
.encodedXml()
|
||||
.encodedXml()
|
||||
.execute();
|
||||
|
||||
|
||||
|
|
|
@ -1972,7 +1972,7 @@ public class SearchBuilder implements ISearchBuilder<JpaPid> {
|
|||
* The loop allows us to create multiple combo index joins if there
|
||||
* are multiple AND expressions for the related parameters.
|
||||
*/
|
||||
while (validateParamValuesAreValidForComboParam(theRequest, theParams, comboParamNames)) {
|
||||
while (validateParamValuesAreValidForComboParam(theRequest, theParams, comboParamNames, comboParam)) {
|
||||
applyComboSearchParam(theQueryStack, theParams, theRequest, comboParamNames, comboParam);
|
||||
}
|
||||
}
|
||||
|
@ -2068,7 +2068,10 @@ public class SearchBuilder implements ISearchBuilder<JpaPid> {
|
|||
* (e.g. <code>?date=gt2024-02-01</code>), etc.
|
||||
*/
|
||||
private boolean validateParamValuesAreValidForComboParam(
|
||||
RequestDetails theRequest, @Nonnull SearchParameterMap theParams, List<String> theComboParamNames) {
|
||||
RequestDetails theRequest,
|
||||
@Nonnull SearchParameterMap theParams,
|
||||
List<String> theComboParamNames,
|
||||
RuntimeSearchParam theComboParam) {
|
||||
boolean paramValuesAreValidForCombo = true;
|
||||
List<List<IQueryParameterType>> paramOrValues = new ArrayList<>(theComboParamNames.size());
|
||||
|
||||
|
@ -2129,6 +2132,19 @@ public class SearchBuilder implements ISearchBuilder<JpaPid> {
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Date params are not eligible for using composite unique index
|
||||
// as index could contain date with different precision (e.g. DAY, SECOND)
|
||||
if (nextParamDef.getParamType() == RestSearchParameterTypeEnum.DATE
|
||||
&& theComboParam.getComboSearchParamType() == ComboSearchParamType.UNIQUE) {
|
||||
ourLog.debug(
|
||||
"Search with params {} is not a candidate for combo searching - "
|
||||
+ "Unique combo search parameter '{}' has DATE type",
|
||||
theComboParamNames,
|
||||
nextParamName);
|
||||
paramValuesAreValidForCombo = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (CartesianProductUtil.calculateCartesianProductSize(paramOrValues) > 500) {
|
||||
|
|
|
@ -566,7 +566,8 @@ public abstract class BaseSearchParamExtractor implements ISearchParamExtractor
|
|||
for (BaseResourceIndexedSearchParam nextParam : paramsListForCompositePart) {
|
||||
IQueryParameterType nextParamAsClientParam = nextParam.toQueryParameterType();
|
||||
|
||||
if (nextParamAsClientParam instanceof DateParam) {
|
||||
if (theParam.getComboSearchParamType() == ComboSearchParamType.NON_UNIQUE
|
||||
&& nextParamAsClientParam instanceof DateParam) {
|
||||
DateParam date = (DateParam) nextParamAsClientParam;
|
||||
if (date.getPrecision() != TemporalPrecisionEnum.DAY) {
|
||||
continue;
|
||||
|
|
|
@ -135,10 +135,10 @@ public abstract class BasePartitioningR4Test extends BaseJpaR4SystemTest {
|
|||
addCreateDefaultPartition();
|
||||
addReadDefaultPartition(); // one for search param validation
|
||||
SearchParameter sp = new SearchParameter();
|
||||
sp.setId("SearchParameter/patient-birthdate");
|
||||
sp.setType(Enumerations.SearchParamType.DATE);
|
||||
sp.setCode("birthdate");
|
||||
sp.setExpression("Patient.birthDate");
|
||||
sp.setId("SearchParameter/patient-gender");
|
||||
sp.setType(Enumerations.SearchParamType.TOKEN);
|
||||
sp.setCode("gender");
|
||||
sp.setExpression("Patient.gender");
|
||||
sp.setStatus(Enumerations.PublicationStatus.ACTIVE);
|
||||
sp.addBase("Patient");
|
||||
mySearchParameterDao.update(sp, mySrd);
|
||||
|
@ -156,13 +156,13 @@ public abstract class BasePartitioningR4Test extends BaseJpaR4SystemTest {
|
|||
|
||||
addCreateDefaultPartition();
|
||||
sp = new SearchParameter();
|
||||
sp.setId("SearchParameter/patient-birthdate-unique");
|
||||
sp.setId("SearchParameter/patient-gender-family-unique");
|
||||
sp.setType(Enumerations.SearchParamType.COMPOSITE);
|
||||
sp.setStatus(Enumerations.PublicationStatus.ACTIVE);
|
||||
sp.addBase("Patient");
|
||||
sp.addComponent()
|
||||
.setExpression("Patient")
|
||||
.setDefinition("SearchParameter/patient-birthdate");
|
||||
.setDefinition("SearchParameter/patient-gender");
|
||||
sp.addComponent()
|
||||
.setExpression("Patient")
|
||||
.setDefinition("SearchParameter/patient-family");
|
||||
|
|
|
@ -13,10 +13,10 @@ import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
|||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.searchparam.util.JpaParamUtil;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.param.DateAndListParam;
|
||||
import ca.uhn.fhir.rest.param.DateOrListParam;
|
||||
import ca.uhn.fhir.rest.param.DateParam;
|
||||
import ca.uhn.fhir.rest.param.ReferenceParam;
|
||||
import ca.uhn.fhir.rest.param.StringOrListParam;
|
||||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
import ca.uhn.fhir.rest.param.TokenAndListParam;
|
||||
import ca.uhn.fhir.rest.param.TokenParam;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
|
||||
|
@ -33,6 +33,7 @@ import org.hl7.fhir.r4.model.DateType;
|
|||
import org.hl7.fhir.r4.model.Encounter;
|
||||
import org.hl7.fhir.r4.model.Enumerations;
|
||||
import org.hl7.fhir.r4.model.Enumerations.PublicationStatus;
|
||||
import org.hl7.fhir.r4.model.HumanName;
|
||||
import org.hl7.fhir.r4.model.IdType;
|
||||
import org.hl7.fhir.r4.model.Observation;
|
||||
import org.hl7.fhir.r4.model.Organization;
|
||||
|
@ -115,6 +116,46 @@ public class FhirResourceDaoR4ComboUniqueParamTest extends BaseComboParamsR4Test
|
|||
myMessages.clear();
|
||||
}
|
||||
|
||||
private void createUniqueGenderFamilyComboSp() {
|
||||
SearchParameter sp = new SearchParameter();
|
||||
sp.setId("SearchParameter/patient-gender");
|
||||
sp.setType(Enumerations.SearchParamType.TOKEN);
|
||||
sp.setCode("gender");
|
||||
sp.setExpression("Patient.gender");
|
||||
sp.setStatus(PublicationStatus.ACTIVE);
|
||||
sp.addBase("Patient");
|
||||
mySearchParameterDao.update(sp, mySrd);
|
||||
|
||||
sp = new SearchParameter();
|
||||
sp.setId("SearchParameter/patient-family");
|
||||
sp.setType(Enumerations.SearchParamType.STRING);
|
||||
sp.setCode("family");
|
||||
sp.setExpression("Patient.name.family");
|
||||
sp.setStatus(Enumerations.PublicationStatus.ACTIVE);
|
||||
sp.addBase("Patient");
|
||||
mySearchParameterDao.update(sp, mySrd);
|
||||
|
||||
sp = new SearchParameter();
|
||||
sp.setId("SearchParameter/patient-gender-family");
|
||||
sp.setType(Enumerations.SearchParamType.COMPOSITE);
|
||||
sp.setStatus(PublicationStatus.ACTIVE);
|
||||
sp.addBase("Patient");
|
||||
sp.addComponent()
|
||||
.setExpression("Patient")
|
||||
.setDefinition("SearchParameter/patient-gender");
|
||||
sp.addComponent()
|
||||
.setExpression("Patient")
|
||||
.setDefinition("SearchParameter/patient-family");
|
||||
sp.addExtension()
|
||||
.setUrl(HapiExtensions.EXT_SP_UNIQUE)
|
||||
.setValue(new BooleanType(true));
|
||||
mySearchParameterDao.update(sp, mySrd);
|
||||
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
myMessages.clear();
|
||||
}
|
||||
|
||||
private void createUniqueIndexCoverageBeneficiary() {
|
||||
SearchParameter sp = new SearchParameter();
|
||||
sp.setId("SearchParameter/coverage-beneficiary");
|
||||
|
@ -276,6 +317,45 @@ public class FhirResourceDaoR4ComboUniqueParamTest extends BaseComboParamsR4Test
|
|||
mySearchParamRegistry.forceRefresh();
|
||||
}
|
||||
|
||||
private void createUniqueObservationDateCode() {
|
||||
SearchParameter sp = new SearchParameter();
|
||||
sp.setId("SearchParameter/obs-effective");
|
||||
sp.setType(Enumerations.SearchParamType.DATE);
|
||||
sp.setCode("date");
|
||||
sp.setExpression("Observation.effective");
|
||||
sp.setStatus(PublicationStatus.ACTIVE);
|
||||
sp.addBase("Observation");
|
||||
mySearchParameterDao.update(sp, mySrd);
|
||||
|
||||
sp = new SearchParameter();
|
||||
sp.setId("SearchParameter/obs-code");
|
||||
sp.setType(Enumerations.SearchParamType.TOKEN);
|
||||
sp.setCode("code");
|
||||
sp.setExpression("Observation.code");
|
||||
sp.setStatus(PublicationStatus.ACTIVE);
|
||||
sp.addBase("Observation");
|
||||
mySearchParameterDao.update(sp, mySrd);
|
||||
|
||||
sp = new SearchParameter();
|
||||
sp.setId("SearchParameter/observation-date-code");
|
||||
sp.setType(Enumerations.SearchParamType.COMPOSITE);
|
||||
sp.setStatus(PublicationStatus.ACTIVE);
|
||||
sp.addBase("Observation");
|
||||
sp.setExpression("Observation.code");
|
||||
sp.addComponent()
|
||||
.setExpression("Observation")
|
||||
.setDefinition("SearchParameter/obs-effective");
|
||||
sp.addComponent()
|
||||
.setExpression("Observation")
|
||||
.setDefinition("SearchParameter/obs-code");
|
||||
sp.addExtension()
|
||||
.setUrl(HapiExtensions.EXT_SP_UNIQUE)
|
||||
.setValue(new BooleanType(true));
|
||||
mySearchParameterDao.update(sp, mySrd);
|
||||
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
}
|
||||
|
||||
private void createUniqueObservationSubjectDateCode() {
|
||||
SearchParameter sp = new SearchParameter();
|
||||
sp.setId("SearchParameter/obs-subject");
|
||||
|
@ -471,11 +551,11 @@ public class FhirResourceDaoR4ComboUniqueParamTest extends BaseComboParamsR4Test
|
|||
public void testDoubleMatchingOnAnd_Search_TwoAndOrValues() {
|
||||
myStorageSettings.setUniqueIndexesCheckedBeforeSave(false);
|
||||
|
||||
createUniqueBirthdateAndGenderSps();
|
||||
createUniqueGenderFamilyComboSp();
|
||||
|
||||
Patient pt1 = new Patient();
|
||||
pt1.setGender(Enumerations.AdministrativeGender.MALE);
|
||||
pt1.setBirthDateElement(new DateType("2011-01-01"));
|
||||
pt1.getName().add(new HumanName().setFamily("Family1"));
|
||||
String id1 = myPatientDao.create(pt1, mySrd).getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
// Two OR values on the same resource - Currently composite SPs don't work for this
|
||||
|
@ -484,17 +564,22 @@ public class FhirResourceDaoR4ComboUniqueParamTest extends BaseComboParamsR4Test
|
|||
sp.setLoadSynchronous(true);
|
||||
sp.add(Patient.SP_GENDER,
|
||||
new TokenAndListParam()
|
||||
.addAnd(new TokenParam("http://hl7.org/fhir/administrative-gender","male"), new TokenParam( "http://hl7.org/fhir/administrative-gender","female"))
|
||||
.addAnd(new TokenParam("http://hl7.org/fhir/administrative-gender","male"),
|
||||
new TokenParam( "http://hl7.org/fhir/administrative-gender","female"))
|
||||
);
|
||||
sp.add(Patient.SP_BIRTHDATE,
|
||||
new DateAndListParam()
|
||||
.addAnd(new DateParam("2011-01-01"), new DateParam( "2011-02-02"))
|
||||
sp.add(Patient.SP_FAMILY,
|
||||
new StringOrListParam()
|
||||
.addOr(new StringParam("Family1")).addOr(new StringParam("Family2"))
|
||||
);
|
||||
IBundleProvider outcome = myPatientDao.search(sp, mySrd);
|
||||
myCaptureQueriesListener.logFirstSelectQueryForCurrentThread();
|
||||
assertThat(toUnqualifiedVersionlessIdValues(outcome)).containsExactlyInAnyOrder(id1);
|
||||
String unformattedSql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(true, false);
|
||||
assertEquals("SELECT t0.RES_ID FROM HFJ_IDX_CMP_STRING_UNIQ t0 WHERE (t0.IDX_STRING IN ('Patient?birthdate=2011-01-01&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cfemale','Patient?birthdate=2011-01-01&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cmale','Patient?birthdate=2011-02-02&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cfemale','Patient?birthdate=2011-02-02&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cmale') )", unformattedSql);
|
||||
assertEquals("SELECT t0.RES_ID FROM HFJ_IDX_CMP_STRING_UNIQ t0 WHERE (t0.IDX_STRING IN (" +
|
||||
"'Patient?family=Family1&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cfemale'," +
|
||||
"'Patient?family=Family1&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cmale'," +
|
||||
"'Patient?family=Family2&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cfemale'," +
|
||||
"'Patient?family=Family2&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cmale') )", unformattedSql);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1167,16 +1252,16 @@ public class FhirResourceDaoR4ComboUniqueParamTest extends BaseComboParamsR4Test
|
|||
@Test
|
||||
public void testOrQuery() {
|
||||
myStorageSettings.setAdvancedHSearchIndexing(false);
|
||||
createUniqueBirthdateAndGenderSps();
|
||||
createUniqueGenderFamilyComboSp();
|
||||
|
||||
Patient pt1 = new Patient();
|
||||
pt1.setGender(Enumerations.AdministrativeGender.MALE);
|
||||
pt1.setBirthDateElement(new DateType("2011-01-01"));
|
||||
pt1.getName().add(new HumanName().setFamily("Family1"));
|
||||
IIdType id1 = myPatientDao.create(pt1, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Patient pt2 = new Patient();
|
||||
pt2.setGender(Enumerations.AdministrativeGender.MALE);
|
||||
pt2.setBirthDateElement(new DateType("2011-01-02"));
|
||||
pt2.getName().add(new HumanName().setFamily("Family2"));
|
||||
IIdType id2 = myPatientDao.create(pt2, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
myCaptureQueriesListener.clear();
|
||||
|
@ -1184,16 +1269,21 @@ public class FhirResourceDaoR4ComboUniqueParamTest extends BaseComboParamsR4Test
|
|||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.setLoadSynchronousUpTo(100);
|
||||
params.add("gender", new TokenParam("http://hl7.org/fhir/administrative-gender", "male"));
|
||||
params.add("birthdate", new DateOrListParam().addOr(new DateParam("2011-01-01")).addOr(new DateParam("2011-01-02")));
|
||||
params.add("family", new StringOrListParam()
|
||||
.addOr(new StringParam("Family1")).addOr(new StringParam("Family2")));
|
||||
myCaptureQueriesListener.clear();
|
||||
IBundleProvider results = myPatientDao.search(params, mySrd);
|
||||
myCaptureQueriesListener.logFirstSelectQueryForCurrentThread();
|
||||
assertThat(toUnqualifiedVersionlessIdValues(results)).containsExactlyInAnyOrder(id1.getValue(), id2.getValue());
|
||||
|
||||
assertThat(myCaptureQueriesListener.getSelectQueries().get(0).getSql(true, false))
|
||||
.contains("SELECT t0.RES_ID FROM HFJ_IDX_CMP_STRING_UNIQ t0 WHERE (t0.IDX_STRING IN ('Patient?birthdate=2011-01-01&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cmale','Patient?birthdate=2011-01-02&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cmale') )");
|
||||
.contains("SELECT t0.RES_ID FROM HFJ_IDX_CMP_STRING_UNIQ t0 WHERE (t0.IDX_STRING IN " +
|
||||
"('Patient?family=Family1&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cmale'," +
|
||||
"'Patient?family=Family2&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cmale') )");
|
||||
logCapturedMessages();
|
||||
assertThat(myMessages.toString()).contains("Using UNIQUE index(es) for query for search: [Patient?birthdate=2011-01-01&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cmale, Patient?birthdate=2011-01-02&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cmale]");
|
||||
assertThat(myMessages.toString()).contains("Using UNIQUE index(es) for query for search: " +
|
||||
"[Patient?family=Family1&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cmale, " +
|
||||
"Patient?family=Family2&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cmale]");
|
||||
myMessages.clear();
|
||||
|
||||
}
|
||||
|
@ -1201,16 +1291,16 @@ public class FhirResourceDaoR4ComboUniqueParamTest extends BaseComboParamsR4Test
|
|||
@Test
|
||||
public void testSearchSynchronousUsingUniqueComposite() {
|
||||
myStorageSettings.setAdvancedHSearchIndexing(false);
|
||||
createUniqueBirthdateAndGenderSps();
|
||||
createUniqueGenderFamilyComboSp();
|
||||
|
||||
Patient pt1 = new Patient();
|
||||
pt1.setGender(Enumerations.AdministrativeGender.MALE);
|
||||
pt1.setBirthDateElement(new DateType("2011-01-01"));
|
||||
pt1.getName().add(new HumanName().setFamily("Family1"));
|
||||
IIdType id1 = myPatientDao.create(pt1, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Patient pt2 = new Patient();
|
||||
pt2.setGender(Enumerations.AdministrativeGender.MALE);
|
||||
pt2.setBirthDateElement(new DateType("2011-01-02"));
|
||||
pt2.getName().add(new HumanName().setFamily("Family2"));
|
||||
myPatientDao.create(pt2, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
myCaptureQueriesListener.clear();
|
||||
|
@ -1218,13 +1308,14 @@ public class FhirResourceDaoR4ComboUniqueParamTest extends BaseComboParamsR4Test
|
|||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.setLoadSynchronousUpTo(100);
|
||||
params.add("gender", new TokenParam("http://hl7.org/fhir/administrative-gender", "male"));
|
||||
params.add("birthdate", new DateParam("2011-01-01"));
|
||||
params.add("family", new StringParam("Family1"));
|
||||
IBundleProvider results = myPatientDao.search(params, mySrd);
|
||||
myCaptureQueriesListener.logFirstSelectQueryForCurrentThread();
|
||||
assertThat(toUnqualifiedVersionlessIdValues(results)).containsExactlyInAnyOrder(id1.getValue());
|
||||
|
||||
logCapturedMessages();
|
||||
assertThat(myMessages.toString()).contains("Using UNIQUE index(es) for query for search: Patient?birthdate=2011-01-01&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cmale");
|
||||
assertThat(myMessages.toString()).contains("Using UNIQUE index(es) for query for search: " +
|
||||
"Patient?family=Family1&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cmale");
|
||||
myMessages.clear();
|
||||
|
||||
}
|
||||
|
@ -1232,33 +1323,34 @@ public class FhirResourceDaoR4ComboUniqueParamTest extends BaseComboParamsR4Test
|
|||
|
||||
@Test
|
||||
public void testSearchUsingUniqueComposite() {
|
||||
createUniqueBirthdateAndGenderSps();
|
||||
createUniqueGenderFamilyComboSp();
|
||||
|
||||
Patient pt1 = new Patient();
|
||||
pt1.setGender(Enumerations.AdministrativeGender.MALE);
|
||||
pt1.setBirthDateElement(new DateType("2011-01-01"));
|
||||
pt1.getName().add(new HumanName().setFamily("Family1"));
|
||||
String id1 = myPatientDao.create(pt1, mySrd).getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
Patient pt2 = new Patient();
|
||||
pt2.setGender(Enumerations.AdministrativeGender.MALE);
|
||||
pt2.setBirthDateElement(new DateType("2011-01-02"));
|
||||
pt2.getName().add(new HumanName().setFamily("Family2"));
|
||||
myPatientDao.create(pt2, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
myMessages.clear();
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.add("gender", new TokenParam("http://hl7.org/fhir/administrative-gender", "male"));
|
||||
params.add("birthdate", new DateParam("2011-01-01"));
|
||||
params.add("family", new StringParam("Family1"));
|
||||
IBundleProvider results = myPatientDao.search(params, mySrd);
|
||||
String searchId = results.getUuid();
|
||||
assertThat(toUnqualifiedVersionlessIdValues(results)).containsExactlyInAnyOrder(id1);
|
||||
logCapturedMessages();
|
||||
assertThat(myMessages.toString()).contains("Using UNIQUE index(es) for query for search: Patient?birthdate=2011-01-01&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cmale");
|
||||
assertThat(myMessages.toString()).contains("Using UNIQUE index(es) for query for search: " +
|
||||
"Patient?family=Family1&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cmale");
|
||||
myMessages.clear();
|
||||
|
||||
// Other order
|
||||
myMessages.clear();
|
||||
params = new SearchParameterMap();
|
||||
params.add("birthdate", new DateParam("2011-01-01"));
|
||||
params.add("family", new StringParam("Family1"));
|
||||
params.add("gender", new TokenParam("http://hl7.org/fhir/administrative-gender", "male"));
|
||||
results = myPatientDao.search(params, mySrd);
|
||||
assertEquals(searchId, results.getUuid());
|
||||
|
@ -1272,16 +1364,17 @@ public class FhirResourceDaoR4ComboUniqueParamTest extends BaseComboParamsR4Test
|
|||
myMessages.clear();
|
||||
params = new SearchParameterMap();
|
||||
params.add("gender", new TokenParam("http://hl7.org/fhir/administrative-gender", "male"));
|
||||
params.add("birthdate", new DateParam("2011-01-03"));
|
||||
params.add("family", new StringParam("Family3"));
|
||||
results = myPatientDao.search(params, mySrd);
|
||||
assertThat(toUnqualifiedVersionlessIdValues(results)).isEmpty();
|
||||
logCapturedMessages();
|
||||
assertThat(myMessages.toString()).contains("Using UNIQUE index(es) for query for search: Patient?birthdate=2011-01-03&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cmale");
|
||||
assertThat(myMessages.toString()).contains("Using UNIQUE index(es) for query for search: " +
|
||||
"Patient?family=Family3&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cmale");
|
||||
myMessages.clear();
|
||||
|
||||
myMessages.clear();
|
||||
params = new SearchParameterMap();
|
||||
params.add("birthdate", new DateParam("2011-01-03"));
|
||||
params.add("family", new StringParam("Family3"));
|
||||
results = myPatientDao.search(params, mySrd);
|
||||
assertThat(toUnqualifiedVersionlessIdValues(results)).isEmpty();
|
||||
// STANDARD QUERY
|
||||
|
@ -1666,7 +1759,7 @@ public class FhirResourceDaoR4ComboUniqueParamTest extends BaseComboParamsR4Test
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testDuplicateUniqueValuesAreRejected() {
|
||||
public void testDuplicateUniqueValuesWithDateAreRejected() {
|
||||
createUniqueBirthdateAndGenderSps();
|
||||
|
||||
Patient pt1 = new Patient();
|
||||
|
@ -1699,13 +1792,75 @@ public class FhirResourceDaoR4ComboUniqueParamTest extends BaseComboParamsR4Test
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testReplaceOneWithAnother() {
|
||||
myStorageSettings.setAdvancedHSearchIndexing(false);
|
||||
public void testDuplicateUniqueValuesWithDateTimeAreRejected() {
|
||||
createUniqueObservationDateCode();
|
||||
|
||||
Observation obs = new Observation();
|
||||
obs.getCode().addCoding().setSystem("foo").setCode("bar");
|
||||
obs.setEffective(new DateTimeType("2017-10-10T00:00:00"));
|
||||
myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
try {
|
||||
myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless();
|
||||
fail();
|
||||
} catch (ResourceVersionConflictException e) {
|
||||
assertThat(e.getMessage())
|
||||
.contains("new unique index created by SearchParameter/observation-date-code");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUniqueComboSearchWithDateNotUsingUniqueIndex() {
|
||||
createUniqueBirthdateAndGenderSps();
|
||||
|
||||
Patient pt1 = new Patient();
|
||||
pt1.setGender(Enumerations.AdministrativeGender.MALE);
|
||||
pt1.setBirthDateElement(new DateType("2011-01-01"));
|
||||
String pId = myPatientDao.create(pt1, mySrd).getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
myCaptureQueriesListener.clear();
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.setLoadSynchronousUpTo(100);
|
||||
params.add("gender", new TokenParam("http://hl7.org/fhir/administrative-gender", "male"));
|
||||
params.add("birthdate", new DateParam("2011-01-01"));
|
||||
|
||||
IBundleProvider results = myPatientDao.search(params, mySrd);
|
||||
assertThat(toUnqualifiedVersionlessIdValues(results)).containsExactlyInAnyOrder(pId);
|
||||
myCaptureQueriesListener.logFirstSelectQueryForCurrentThread();
|
||||
String unformattedSql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(true, false);
|
||||
assertThat(unformattedSql).doesNotContain("HFJ_IDX_CMP_STRING_UNIQ");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUniqueComboSearchWithDateTimeNotUsingUniqueIndex() {
|
||||
createUniqueObservationDateCode();
|
||||
|
||||
Observation obs = new Observation();
|
||||
obs.getCode().addCoding().setSystem("foo").setCode("bar");
|
||||
obs.setEffective(new DateTimeType("2017-10-10T00:00:00"));
|
||||
String obsId = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
myCaptureQueriesListener.clear();
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.setLoadSynchronousUpTo(100);
|
||||
params.add("code", new TokenParam("foo", "bar"));
|
||||
params.add("date", new DateParam("2017-10-10T00:00:00"));
|
||||
|
||||
IBundleProvider results = myObservationDao.search(params, mySrd);
|
||||
assertThat(toUnqualifiedVersionlessIdValues(results)).containsExactlyInAnyOrder(obsId);
|
||||
myCaptureQueriesListener.logFirstSelectQueryForCurrentThread();
|
||||
String unformattedSql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(true, false);
|
||||
assertThat(unformattedSql).doesNotContain("HFJ_IDX_CMP_STRING_UNIQ");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReplaceOneWithAnother() {
|
||||
myStorageSettings.setAdvancedHSearchIndexing(false);
|
||||
createUniqueGenderFamilyComboSp();
|
||||
|
||||
Patient pt1 = new Patient();
|
||||
pt1.setGender(Enumerations.AdministrativeGender.MALE);
|
||||
pt1.getName().add(new HumanName().setFamily("Family1"));
|
||||
IIdType id1 = myPatientDao.create(pt1, mySrd).getId().toUnqualified();
|
||||
assertNotNull(id1);
|
||||
|
||||
|
@ -1714,27 +1869,28 @@ public class FhirResourceDaoR4ComboUniqueParamTest extends BaseComboParamsR4Test
|
|||
pt1 = new Patient();
|
||||
pt1.setId(id1);
|
||||
pt1.setGender(Enumerations.AdministrativeGender.FEMALE);
|
||||
pt1.setBirthDateElement(new DateType("2011-01-01"));
|
||||
pt1.getName().add(new HumanName().setFamily("Family1"));
|
||||
id1 = myPatientDao.update(pt1, mySrd).getId().toUnqualified();
|
||||
assertNotNull(id1);
|
||||
assertEquals("2", id1.getVersionIdPart());
|
||||
|
||||
Patient pt2 = new Patient();
|
||||
pt2.setGender(Enumerations.AdministrativeGender.MALE);
|
||||
pt2.setBirthDateElement(new DateType("2011-01-01"));
|
||||
pt2.getName().add(new HumanName().setFamily("Family1"));
|
||||
IIdType id2 = myPatientDao.create(pt2, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
myMessages.clear();
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.add("gender", new TokenParam("http://hl7.org/fhir/administrative-gender", "male"));
|
||||
params.add("birthdate", new DateParam("2011-01-01"));
|
||||
params.add("family", new StringParam("Family1"));
|
||||
IBundleProvider results = myPatientDao.search(params, mySrd);
|
||||
String searchId = results.getUuid();
|
||||
assertThat(searchId).isNotBlank();
|
||||
assertThat(toUnqualifiedVersionlessIdValues(results)).containsExactlyInAnyOrder(id2.getValue());
|
||||
|
||||
logCapturedMessages();
|
||||
assertThat(myMessages.toString()).contains("Using UNIQUE index(es) for query for search: Patient?birthdate=2011-01-01&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cmale");
|
||||
assertThat(myMessages.toString()).contains("Using UNIQUE index(es) for query for search: " +
|
||||
"Patient?family=Family1&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cmale");
|
||||
myMessages.clear();
|
||||
|
||||
}
|
||||
|
|
|
@ -413,7 +413,7 @@ public class PartitioningSqlR4Test extends BasePartitioningR4Test {
|
|||
p.getMeta().addTag("http://system", "code", "diisplay");
|
||||
p.addName().setFamily("FAM");
|
||||
p.addIdentifier().setSystem("system").setValue("value");
|
||||
p.setBirthDateElement(new DateType("2020-01-01"));
|
||||
p.setGender(Enumerations.AdministrativeGender.MALE);
|
||||
p.getManagingOrganization().setReferenceElement(orgId);
|
||||
Long patientId = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
||||
|
||||
|
@ -502,7 +502,7 @@ public class PartitioningSqlR4Test extends BasePartitioningR4Test {
|
|||
p.getMeta().addTag("http://system", "code", "diisplay");
|
||||
p.addName().setFamily("FAM");
|
||||
p.addIdentifier().setSystem("system").setValue("value");
|
||||
p.setBirthDate(new Date());
|
||||
p.setGender(Enumerations.AdministrativeGender.MALE);
|
||||
p.getManagingOrganization().setReferenceElement(orgId);
|
||||
Long patientId = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
||||
|
||||
|
@ -679,7 +679,7 @@ public class PartitioningSqlR4Test extends BasePartitioningR4Test {
|
|||
p.getMeta().addTag("http://system", "code", "display");
|
||||
p.addName().setFamily("FAM");
|
||||
p.addIdentifier().setSystem("system").setValue("value");
|
||||
p.setBirthDate(new Date());
|
||||
p.setGender(Enumerations.AdministrativeGender.MALE);
|
||||
p.getManagingOrganization().setReference(org.getId());
|
||||
input.addEntry()
|
||||
.setFullUrl(p.getId())
|
||||
|
@ -2541,14 +2541,14 @@ public class PartitioningSqlR4Test extends BasePartitioningR4Test {
|
|||
public void testSearch_UniqueParam_SearchAllPartitions() {
|
||||
createUniqueComboSp();
|
||||
|
||||
IIdType id = createPatient(withPartition(1), withBirthdate("2020-01-01"), withFamily("FAM"));
|
||||
IIdType id = createPatient(withPartition(1), withGender("male"), withFamily("FAM"));
|
||||
|
||||
addReadAllPartitions();
|
||||
|
||||
myCaptureQueriesListener.clear();
|
||||
SearchParameterMap map = new SearchParameterMap();
|
||||
map.add(Patient.SP_FAMILY, new StringParam("FAM"));
|
||||
map.add(Patient.SP_BIRTHDATE, new DateParam("2020-01-01"));
|
||||
map.add(Patient.SP_GENDER, new TokenParam(null, "male"));
|
||||
map.setLoadSynchronous(true);
|
||||
IBundleProvider results = myPatientDao.search(map, mySrd);
|
||||
List<IIdType> ids = toUnqualifiedVersionlessIds(results);
|
||||
|
@ -2558,7 +2558,7 @@ public class PartitioningSqlR4Test extends BasePartitioningR4Test {
|
|||
String searchSql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(true, true);
|
||||
ourLog.info("Search SQL:\n{}", searchSql);
|
||||
assertThat(searchSql).doesNotContain("PARTITION_ID");
|
||||
assertThat(searchSql).containsOnlyOnce("IDX_STRING = 'Patient?birthdate=2020-01-01&family=FAM'");
|
||||
assertThat(searchSql).containsOnlyOnce("IDX_STRING = 'Patient?family=FAM&gender=male'");
|
||||
}
|
||||
|
||||
|
||||
|
@ -2566,13 +2566,13 @@ public class PartitioningSqlR4Test extends BasePartitioningR4Test {
|
|||
public void testSearch_UniqueParam_SearchOnePartition() {
|
||||
createUniqueComboSp();
|
||||
|
||||
IIdType id = createPatient(withPartition(1), withBirthdate("2020-01-01"), withFamily("FAM"));
|
||||
IIdType id = createPatient(withPartition(1), withGender("male"), withFamily("FAM"));
|
||||
|
||||
addReadPartition(1);
|
||||
myCaptureQueriesListener.clear();
|
||||
SearchParameterMap map = new SearchParameterMap();
|
||||
map.add(Patient.SP_FAMILY, new StringParam("FAM"));
|
||||
map.add(Patient.SP_BIRTHDATE, new DateParam("2020-01-01"));
|
||||
map.add(Patient.SP_GENDER, new TokenParam(null, "male"));
|
||||
map.setLoadSynchronous(true);
|
||||
IBundleProvider results = myPatientDao.search(map, mySrd);
|
||||
List<IIdType> ids = toUnqualifiedVersionlessIds(results);
|
||||
|
@ -2582,13 +2582,13 @@ public class PartitioningSqlR4Test extends BasePartitioningR4Test {
|
|||
String searchSql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(true, true);
|
||||
ourLog.info("Search SQL:\n{}", searchSql);
|
||||
assertThat(searchSql).containsOnlyOnce( "PARTITION_ID = '1'");
|
||||
assertThat(searchSql).containsOnlyOnce("IDX_STRING = 'Patient?birthdate=2020-01-01&family=FAM'");
|
||||
assertThat(searchSql).containsOnlyOnce("IDX_STRING = 'Patient?family=FAM&gender=male'");
|
||||
|
||||
// Same query, different partition
|
||||
addReadPartition(2);
|
||||
myCaptureQueriesListener.clear();
|
||||
map = new SearchParameterMap();
|
||||
map.add(Patient.SP_BIRTHDATE, new DateParam("2020-01-01"));
|
||||
map.add(Patient.SP_GENDER, new TokenParam(null, "male"));
|
||||
map.setLoadSynchronous(true);
|
||||
results = myPatientDao.search(map, mySrd);
|
||||
ids = toUnqualifiedVersionlessIds(results);
|
||||
|
@ -2661,7 +2661,7 @@ public class PartitioningSqlR4Test extends BasePartitioningR4Test {
|
|||
public void testSearch_RefParam_TargetPid_SearchOnePartition() {
|
||||
createUniqueComboSp();
|
||||
|
||||
IIdType patientId = createPatient(withPartition(myPartitionId), withBirthdate("2020-01-01"));
|
||||
IIdType patientId = createPatient(withPartition(myPartitionId), withGender("male"));
|
||||
IIdType observationId = createObservation(withPartition(myPartitionId), withSubject(patientId));
|
||||
|
||||
addReadPartition(myPartitionId);
|
||||
|
@ -2698,7 +2698,7 @@ public class PartitioningSqlR4Test extends BasePartitioningR4Test {
|
|||
public void testSearch_RefParam_TargetPid_SearchDefaultPartition() {
|
||||
createUniqueComboSp();
|
||||
|
||||
IIdType patientId = createPatient(withPartition(null), withBirthdate("2020-01-01"));
|
||||
IIdType patientId = createPatient(withPartition(null), withGender("male"));
|
||||
IIdType observationId = createObservation(withPartition(null), withSubject(patientId));
|
||||
|
||||
addReadDefaultPartition();
|
||||
|
@ -2735,7 +2735,7 @@ public class PartitioningSqlR4Test extends BasePartitioningR4Test {
|
|||
public void testSearch_RefParam_TargetForcedId_SearchOnePartition() {
|
||||
createUniqueComboSp();
|
||||
|
||||
IIdType patientId = createPatient(withPartition(myPartitionId), withId("ONE"), withBirthdate("2020-01-01"));
|
||||
IIdType patientId = createPatient(withPartition(myPartitionId), withId("ONE"), withGender("male"));
|
||||
IIdType observationId = createObservation(withPartition(myPartitionId), withSubject(patientId));
|
||||
|
||||
addReadPartition(myPartitionId);
|
||||
|
@ -2805,7 +2805,7 @@ public class PartitioningSqlR4Test extends BasePartitioningR4Test {
|
|||
public void testSearch_RefParam_TargetForcedId_SearchDefaultPartition() {
|
||||
createUniqueComboSp();
|
||||
|
||||
IIdType patientId = createPatient(withPartition(null), withId("ONE"), withBirthdate("2020-01-01"));
|
||||
IIdType patientId = createPatient(withPartition(null), withId("ONE"), withGender("male"));
|
||||
IIdType observationId = createObservation(withPartition(null), withSubject(patientId));
|
||||
|
||||
addReadDefaultPartition();
|
||||
|
|
|
@ -64,6 +64,7 @@ import ca.uhn.fhir.util.UrlUtil;
|
|||
import com.google.common.base.Charsets;
|
||||
import com.google.common.collect.Lists;
|
||||
import jakarta.annotation.Nonnull;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
@ -168,6 +169,7 @@ import org.junit.jupiter.api.AfterEach;
|
|||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Order;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
|
@ -188,6 +190,9 @@ import java.net.InetSocketAddress;
|
|||
import java.net.Socket;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
|
@ -196,6 +201,7 @@ import java.util.Date;
|
|||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
|
@ -205,6 +211,7 @@ import static ca.uhn.fhir.util.TestUtil.sleepAtLeast;
|
|||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;
|
||||
import static org.awaitility.Awaitility.await;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
@ -263,6 +270,73 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
|||
myStorageSettings.setSearchPreFetchThresholds(new JpaStorageSettings().getSearchPreFetchThresholds());
|
||||
}
|
||||
|
||||
/**
|
||||
* We set to run last because we alter our client configs,
|
||||
* and we don't want to break tests that create new clients
|
||||
* (with an expectation of a different set of configs)
|
||||
* after this test.
|
||||
*/
|
||||
@Order(Integer.MAX_VALUE)
|
||||
@Test
|
||||
public void testGenericClient_preservesClientSettings() {
|
||||
// setup
|
||||
int socketTimeout = 700;
|
||||
int delay = 1200;
|
||||
String clientHeader = "client";
|
||||
|
||||
// we register a delaying interceptor for all requests to this server
|
||||
Object interceptor = new Object() {
|
||||
@Hook(Pointcut.SERVER_INCOMING_REQUEST_PRE_PROCESSED)
|
||||
public void intercept(HttpServletRequest theRequest) {
|
||||
Instant start = Instant.now();
|
||||
Instant endTime = Instant.now().plus(delay, ChronoUnit.MILLIS);
|
||||
|
||||
await()
|
||||
.atLeast(socketTimeout, TimeUnit.MILLISECONDS)
|
||||
.atMost(delay + socketTimeout, TimeUnit.MILLISECONDS)
|
||||
.until(() -> {
|
||||
return Instant.now().isAfter(endTime);
|
||||
});
|
||||
|
||||
ourLog.info("Delayed {}ms for server request from {}",
|
||||
Instant.now().toEpochMilli() - start.toEpochMilli(),
|
||||
theRequest.getHeader(clientHeader));
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
myServer.getInterceptorService().registerInterceptor(interceptor);
|
||||
|
||||
// get a first client with our short timeout
|
||||
myFhirContext.getRestfulClientFactory().setSocketTimeout(socketTimeout);
|
||||
IGenericClient client1 = myFhirContext.newRestfulGenericClient(myServerBase);
|
||||
|
||||
// get a second client with a longer timeout
|
||||
myFhirContext.getRestfulClientFactory().setSocketTimeout((int)Duration.of(10, ChronoUnit.SECONDS).toMillis());
|
||||
IGenericClient client2 = myFhirContext.newRestfulGenericClient(myServerBase);
|
||||
|
||||
try {
|
||||
// should fail
|
||||
client1.search()
|
||||
.forResource("Patient")
|
||||
.withAdditionalHeader(clientHeader, "client1")
|
||||
.execute();
|
||||
fail();
|
||||
} catch (Exception ex) {
|
||||
assertTrue(ex.getMessage().contains("SocketTimeoutException"));
|
||||
}
|
||||
|
||||
// should not fail
|
||||
IBaseBundle result = client2.search()
|
||||
.forResource("Patient")
|
||||
.withAdditionalHeader(clientHeader, "client2")
|
||||
.execute();
|
||||
assertNotNull(result);
|
||||
} finally {
|
||||
myServer.getInterceptorService().unregisterInterceptor(interceptor);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParameterWithNoValueThrowsError_InvalidChainOnCustomSearch() throws IOException {
|
||||
SearchParameter searchParameter = new SearchParameter();
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package ca.uhn.fhir.rest.client;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.parser.IParser;
|
||||
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||
|
@ -11,6 +10,7 @@ import ca.uhn.fhir.rest.annotation.Validate;
|
|||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.api.ValidationModeEnum;
|
||||
import ca.uhn.fhir.rest.client.apache.ApacheRestfulClientFactory;
|
||||
import ca.uhn.fhir.rest.client.api.IRestfulClient;
|
||||
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
|
||||
import ca.uhn.fhir.system.HapiSystemProperties;
|
||||
|
@ -44,6 +44,7 @@ import java.nio.charset.Charset;
|
|||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
|
@ -54,13 +55,13 @@ public class NonGenericClientDstu2_1Test {
|
|||
|
||||
@BeforeEach
|
||||
public void before() {
|
||||
ourCtx.setRestfulClientFactory(new ApacheRestfulClientFactory(ourCtx));
|
||||
myHttpClient = mock(HttpClient.class, new ReturnsDeepStubs());
|
||||
ourCtx.getRestfulClientFactory().setHttpClient(myHttpClient);
|
||||
ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
|
||||
myHttpResponse = mock(HttpResponse.class, new ReturnsDeepStubs());
|
||||
|
||||
HapiSystemProperties.enableHapiClientKeepResponses();
|
||||
|
||||
}
|
||||
|
||||
private String extractBodyAsString(ArgumentCaptor<HttpUriRequest> capt, int theIdx) throws IOException {
|
||||
|
|
|
@ -11,6 +11,7 @@ import ca.uhn.fhir.rest.annotation.Validate;
|
|||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.api.ValidationModeEnum;
|
||||
import ca.uhn.fhir.rest.client.apache.ApacheRestfulClientFactory;
|
||||
import ca.uhn.fhir.rest.client.api.IRestfulClient;
|
||||
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
|
||||
import ca.uhn.fhir.system.HapiSystemProperties;
|
||||
|
@ -54,6 +55,7 @@ public class NonGenericClientDstu3Test {
|
|||
|
||||
@BeforeEach
|
||||
public void before() {
|
||||
ourCtx.setRestfulClientFactory(new ApacheRestfulClientFactory(ourCtx));
|
||||
myHttpClient = mock(HttpClient.class, new ReturnsDeepStubs());
|
||||
ourCtx.getRestfulClientFactory().setHttpClient(myHttpClient);
|
||||
ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
|
||||
|
|
|
@ -19,12 +19,14 @@ import ca.uhn.fhir.rest.api.EncodingEnum;
|
|||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.api.SummaryEnum;
|
||||
import ca.uhn.fhir.rest.client.apache.ApacheHttpRequest;
|
||||
import ca.uhn.fhir.rest.client.apache.ApacheRestfulClientFactory;
|
||||
import ca.uhn.fhir.rest.client.apache.ResourceEntity;
|
||||
import ca.uhn.fhir.rest.client.api.IBasicClient;
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import ca.uhn.fhir.rest.client.api.IRestfulClient;
|
||||
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
|
||||
import ca.uhn.fhir.rest.client.exceptions.FhirClientConnectionException;
|
||||
import ca.uhn.fhir.rest.client.impl.RestfulClientFactory;
|
||||
import ca.uhn.fhir.rest.client.interceptor.CapturingInterceptor;
|
||||
import ca.uhn.fhir.rest.param.CompositeParam;
|
||||
import ca.uhn.fhir.rest.param.DateParam;
|
||||
|
@ -108,7 +110,9 @@ public class ClientR4Test {
|
|||
|
||||
@BeforeEach
|
||||
public void before() {
|
||||
|
||||
// we want to reset the client factory so we aren't handing back previously used
|
||||
// test clients
|
||||
ourCtx.setRestfulClientFactory(new ApacheRestfulClientFactory(ourCtx));
|
||||
myHttpClient = mock(HttpClient.class, new ReturnsDeepStubs());
|
||||
ourCtx.getRestfulClientFactory().setHttpClient(myHttpClient);
|
||||
ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
|
||||
|
|
|
@ -10,6 +10,7 @@ import ca.uhn.fhir.rest.annotation.Validate;
|
|||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.api.ValidationModeEnum;
|
||||
import ca.uhn.fhir.rest.client.apache.ApacheRestfulClientFactory;
|
||||
import ca.uhn.fhir.rest.client.api.IRestfulClient;
|
||||
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
|
||||
import ca.uhn.fhir.system.HapiSystemProperties;
|
||||
|
@ -54,6 +55,8 @@ public class NonGenericClientR4Test {
|
|||
|
||||
@BeforeEach
|
||||
public void before() {
|
||||
// reset our client factory so we don't reuse test clients
|
||||
ourCtx.setRestfulClientFactory(new ApacheRestfulClientFactory(ourCtx));
|
||||
myHttpClient = mock(HttpClient.class, new ReturnsDeepStubs());
|
||||
ourCtx.getRestfulClientFactory().setHttpClient(myHttpClient);
|
||||
ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
|
||||
|
|
Loading…
Reference in New Issue