Merge branch 'jaxrs-client'

This commit is contained in:
jamesagnew 2016-02-27 09:48:51 -05:00
commit a818ba199c
66 changed files with 2195 additions and 648 deletions

View File

@ -3,11 +3,11 @@ package example;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.client.IGenericClient; import ca.uhn.fhir.rest.client.IGenericClient;
import ca.uhn.fhir.rest.client.IRestfulClientFactory; import ca.uhn.fhir.rest.client.IRestfulClientFactory;
import ca.uhn.fhir.rest.client.apache.GZipContentInterceptor;
import ca.uhn.fhir.rest.client.api.IBasicClient; import ca.uhn.fhir.rest.client.api.IBasicClient;
import ca.uhn.fhir.rest.client.interceptor.BasicAuthInterceptor; import ca.uhn.fhir.rest.client.interceptor.BasicAuthInterceptor;
import ca.uhn.fhir.rest.client.interceptor.BearerTokenAuthInterceptor; import ca.uhn.fhir.rest.client.interceptor.BearerTokenAuthInterceptor;
import ca.uhn.fhir.rest.client.interceptor.CookieInterceptor; import ca.uhn.fhir.rest.client.interceptor.CookieInterceptor;
import ca.uhn.fhir.rest.client.interceptor.GZipContentInterceptor;
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor; import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
import ca.uhn.fhir.rest.server.EncodingEnum; import ca.uhn.fhir.rest.server.EncodingEnum;

View File

@ -47,7 +47,7 @@ import ca.uhn.fhir.parser.LenientErrorHandler;
import ca.uhn.fhir.parser.XmlParser; import ca.uhn.fhir.parser.XmlParser;
import ca.uhn.fhir.rest.client.IGenericClient; import ca.uhn.fhir.rest.client.IGenericClient;
import ca.uhn.fhir.rest.client.IRestfulClientFactory; import ca.uhn.fhir.rest.client.IRestfulClientFactory;
import ca.uhn.fhir.rest.client.RestfulClientFactory; import ca.uhn.fhir.rest.client.apache.ApacheRestfulClientFactory;
import ca.uhn.fhir.rest.client.api.IBasicClient; import ca.uhn.fhir.rest.client.api.IBasicClient;
import ca.uhn.fhir.rest.client.api.IRestfulClient; import ca.uhn.fhir.rest.client.api.IRestfulClient;
import ca.uhn.fhir.rest.server.IVersionSpecificBundleFactory; import ca.uhn.fhir.rest.server.IVersionSpecificBundleFactory;
@ -298,9 +298,22 @@ public class FhirContext {
return myIdToResourceDefinition.values(); return myIdToResourceDefinition.values();
} }
/**
* Set the restful client factory
* @param theRestfulClientFactory
*/
public void setRestfulClientFactory(IRestfulClientFactory theRestfulClientFactory) {
this.myRestfulClientFactory = theRestfulClientFactory;
}
/**
* Get the restful client factory. If no factory has been set, this will be initialized with
* a new ApacheRestfulClientFactory.
* @return the factory used to create the restful clients
*/
public IRestfulClientFactory getRestfulClientFactory() { public IRestfulClientFactory getRestfulClientFactory() {
if (myRestfulClientFactory == null) { if (myRestfulClientFactory == null) {
myRestfulClientFactory = new RestfulClientFactory(this); myRestfulClientFactory = new ApacheRestfulClientFactory(this);
} }
return myRestfulClientFactory; return myRestfulClientFactory;
} }

View File

@ -25,10 +25,8 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader; import java.io.Reader;
import java.io.StringReader; import java.io.StringReader;
import java.nio.charset.Charset;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
@ -40,14 +38,6 @@ import java.util.Set;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.Validate;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.ContentType;
import org.hl7.fhir.instance.model.api.IBase; import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome; import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
@ -62,6 +52,9 @@ import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.parser.DataFormatException; import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.parser.IParser; import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.api.SummaryEnum; import ca.uhn.fhir.rest.api.SummaryEnum;
import ca.uhn.fhir.rest.client.api.IHttpClient;
import ca.uhn.fhir.rest.client.api.IHttpRequest;
import ca.uhn.fhir.rest.client.api.IHttpResponse;
import ca.uhn.fhir.rest.client.api.IRestfulClient; import ca.uhn.fhir.rest.client.api.IRestfulClient;
import ca.uhn.fhir.rest.client.exceptions.FhirClientConnectionException; import ca.uhn.fhir.rest.client.exceptions.FhirClientConnectionException;
import ca.uhn.fhir.rest.client.exceptions.InvalidResponseException; import ca.uhn.fhir.rest.client.exceptions.InvalidResponseException;
@ -79,19 +72,19 @@ public abstract class BaseClient implements IRestfulClient {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseClient.class); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseClient.class);
private final HttpClient myClient; private final IHttpClient myClient;
private boolean myDontValidateConformance; private boolean myDontValidateConformance;
private EncodingEnum myEncoding = null; // default unspecified (will be XML) private EncodingEnum myEncoding = null; // default unspecified (will be XML)
private final RestfulClientFactory myFactory; private final RestfulClientFactory myFactory;
private List<IClientInterceptor> myInterceptors = new ArrayList<IClientInterceptor>(); private List<IClientInterceptor> myInterceptors = new ArrayList<IClientInterceptor>();
private boolean myKeepResponses = false; private boolean myKeepResponses = false;
private HttpResponse myLastResponse; private IHttpResponse myLastResponse;
private String myLastResponseBody; private String myLastResponseBody;
private Boolean myPrettyPrint = false; private Boolean myPrettyPrint = false;
private SummaryEnum mySummary; private SummaryEnum mySummary;
private final String myUrlBase; private final String myUrlBase;
BaseClient(HttpClient theClient, String theUrlBase, RestfulClientFactory theFactory) { BaseClient(IHttpClient theClient, String theUrlBase, RestfulClientFactory theFactory) {
super(); super();
myClient = theClient; myClient = theClient;
myUrlBase = theUrlBase; myUrlBase = theUrlBase;
@ -130,7 +123,7 @@ public abstract class BaseClient implements IRestfulClient {
* {@inheritDoc} * {@inheritDoc}
*/ */
@Override @Override
public HttpClient getHttpClient() { public IHttpClient getHttpClient() {
return myClient; return myClient;
} }
@ -141,7 +134,7 @@ public abstract class BaseClient implements IRestfulClient {
/** /**
* For now, this is a part of the internal API of HAPI - Use with caution as this method may change! * For now, this is a part of the internal API of HAPI - Use with caution as this method may change!
*/ */
public HttpResponse getLastResponse() { public IHttpResponse getLastResponse() {
return myLastResponse; return myLastResponse;
} }
@ -193,46 +186,43 @@ public abstract class BaseClient implements IRestfulClient {
// TODO: handle non 2xx status codes by throwing the correct exception, // TODO: handle non 2xx status codes by throwing the correct exception,
// and ensure it's passed upwards // and ensure it's passed upwards
HttpRequestBase httpRequest; IHttpRequest httpRequest;
HttpResponse response; IHttpResponse response = null;
try { try {
Map<String, List<String>> params = createExtraParams(); Map<String, List<String>> params = createExtraParams();
if (theEncoding == EncodingEnum.XML) { if (theEncoding == EncodingEnum.XML) {
params.put(Constants.PARAM_FORMAT, Collections.singletonList("xml")); params.put(Constants.PARAM_FORMAT, Collections.singletonList("xml"));
} else if (theEncoding == EncodingEnum.JSON) { } else if (theEncoding == EncodingEnum.JSON) {
params.put(Constants.PARAM_FORMAT, Collections.singletonList("json")); params.put(Constants.PARAM_FORMAT, Collections.singletonList("json"));
} }
if (theSummaryMode != null) { if (theSummaryMode != null) {
params.put(Constants.PARAM_SUMMARY, Collections.singletonList(theSummaryMode.getCode())); params.put(Constants.PARAM_SUMMARY, Collections.singletonList(theSummaryMode.getCode()));
} else if (mySummary != null) { } else if (mySummary != null) {
params.put(Constants.PARAM_SUMMARY, Collections.singletonList(mySummary.getCode())); params.put(Constants.PARAM_SUMMARY, Collections.singletonList(mySummary.getCode()));
} }
if (thePrettyPrint == Boolean.TRUE) { if (thePrettyPrint == Boolean.TRUE) {
params.put(Constants.PARAM_PRETTY, Collections.singletonList(Constants.PARAM_PRETTY_VALUE_TRUE)); params.put(Constants.PARAM_PRETTY, Collections.singletonList(Constants.PARAM_PRETTY_VALUE_TRUE));
} }
if (theSubsetElements != null && theSubsetElements.isEmpty() == false) { if (theSubsetElements != null && theSubsetElements.isEmpty() == false) {
params.put(Constants.PARAM_ELEMENTS, Collections.singletonList(StringUtils.join(theSubsetElements, ','))); params.put(Constants.PARAM_ELEMENTS, Collections.singletonList(StringUtils.join(theSubsetElements, ',')));
} }
EncodingEnum encoding = getEncoding(); EncodingEnum encoding = getEncoding();
if (theEncoding != null) { if (theEncoding != null) {
encoding = theEncoding; encoding = theEncoding;
} }
httpRequest = clientInvocation.asHttpRequest(myUrlBase, params, encoding, thePrettyPrint); httpRequest = clientInvocation.asHttpRequest(myUrlBase, params, encoding, thePrettyPrint);
if (theLogRequestAndResponse) { if (theLogRequestAndResponse) {
ourLog.info("Client invoking: {}", httpRequest); ourLog.info("Client invoking: {}", httpRequest);
if (httpRequest instanceof HttpEntityEnclosingRequest) { String body = httpRequest.getRequestBodyFromStream();
HttpEntity entity = ((HttpEntityEnclosingRequest) httpRequest).getEntity(); if(body != null) {
if (entity.isRepeatable()) { ourLog.info("Client request body: {}", body);
String content = IOUtils.toString(entity.getContent());
ourLog.info("Client request body: {}", content);
}
} }
} }
@ -240,45 +230,26 @@ public abstract class BaseClient implements IRestfulClient {
nextInterceptor.interceptRequest(httpRequest); nextInterceptor.interceptRequest(httpRequest);
} }
response = myClient.execute(httpRequest); response = httpRequest.execute();
for (IClientInterceptor nextInterceptor : myInterceptors) { for (IClientInterceptor nextInterceptor : myInterceptors) {
nextInterceptor.interceptResponse(response); nextInterceptor.interceptResponse(response);
} }
} catch (DataFormatException e) {
throw new FhirClientConnectionException(e);
} catch (IOException e) {
throw new FhirClientConnectionException(e);
}
try {
String mimeType; String mimeType;
if (Constants.STATUS_HTTP_204_NO_CONTENT == response.getStatusLine().getStatusCode()) { if (Constants.STATUS_HTTP_204_NO_CONTENT == response.getStatus()) {
mimeType = null; mimeType = null;
} else { } else {
ContentType ct = ContentType.get(response.getEntity()); mimeType = response.getMimeType();
mimeType = ct != null ? ct.getMimeType() : null;
} }
Map<String, List<String>> headers = new HashMap<String, List<String>>(); Map<String, List<String>> headers = response.getAllHeaders();
if (response.getAllHeaders() != null) {
for (Header next : response.getAllHeaders()) {
String name = next.getName().toLowerCase();
List<String> list = headers.get(name);
if (list == null) {
list = new ArrayList<String>();
headers.put(name, list);
}
list.add(next.getValue());
}
}
if (response.getStatusLine().getStatusCode() < 200 || response.getStatusLine().getStatusCode() > 299) { if (response.getStatus() < 200 || response.getStatus() > 299) {
String body = null; String body = null;
Reader reader = null; Reader reader = null;
try { try {
reader = createReaderFromResponse(response); reader = response.createReader();
body = IOUtils.toString(reader); body = IOUtils.toString(reader);
} catch (Exception e) { } catch (Exception e) {
ourLog.debug("Failed to read input stream", e); ourLog.debug("Failed to read input stream", e);
@ -286,7 +257,7 @@ public abstract class BaseClient implements IRestfulClient {
IOUtils.closeQuietly(reader); IOUtils.closeQuietly(reader);
} }
String message = "HTTP " + response.getStatusLine().getStatusCode() + " " + response.getStatusLine().getReasonPhrase(); String message = "HTTP " + response.getStatus() + " " + response.getStatusInfo();
IBaseOperationOutcome oo = null; IBaseOperationOutcome oo = null;
if (Constants.CT_TEXT.equals(mimeType)) { if (Constants.CT_TEXT.equals(mimeType)) {
message = message + ": " + body; message = message + ": " + body;
@ -309,7 +280,7 @@ public abstract class BaseClient implements IRestfulClient {
keepResponseAndLogIt(theLogRequestAndResponse, response, body); keepResponseAndLogIt(theLogRequestAndResponse, response, body);
BaseServerResponseException exception = BaseServerResponseException.newInstance(response.getStatusLine().getStatusCode(), message); BaseServerResponseException exception = BaseServerResponseException.newInstance(response.getStatus(), message);
exception.setOperationOutcome(oo); exception.setOperationOutcome(oo);
if (body != null) { if (body != null) {
@ -321,7 +292,7 @@ public abstract class BaseClient implements IRestfulClient {
if (binding instanceof IClientResponseHandlerHandlesBinary) { if (binding instanceof IClientResponseHandlerHandlesBinary) {
IClientResponseHandlerHandlesBinary<T> handlesBinary = (IClientResponseHandlerHandlesBinary<T>) binding; IClientResponseHandlerHandlesBinary<T> handlesBinary = (IClientResponseHandlerHandlesBinary<T>) binding;
if (handlesBinary.isBinary()) { if (handlesBinary.isBinary()) {
InputStream reader = response.getEntity().getContent(); InputStream reader = response.readEntity();
try { try {
if (ourLog.isTraceEnabled() || myKeepResponses || theLogRequestAndResponse) { if (ourLog.isTraceEnabled() || myKeepResponses || theLogRequestAndResponse) {
@ -330,7 +301,7 @@ public abstract class BaseClient implements IRestfulClient {
myLastResponse = response; myLastResponse = response;
myLastResponseBody = null; myLastResponseBody = null;
} }
String message = "HTTP " + response.getStatusLine().getStatusCode() + " " + response.getStatusLine().getReasonPhrase(); String message = "HTTP " + response.getStatus() + " " + response.getStatusInfo();
if (theLogRequestAndResponse) { if (theLogRequestAndResponse) {
ourLog.info("Client response: {} - {} bytes", message, responseBytes.length); ourLog.info("Client response: {} - {} bytes", message, responseBytes.length);
} else { } else {
@ -339,14 +310,14 @@ public abstract class BaseClient implements IRestfulClient {
reader = new ByteArrayInputStream(responseBytes); reader = new ByteArrayInputStream(responseBytes);
} }
return handlesBinary.invokeClient(mimeType, reader, response.getStatusLine().getStatusCode(), headers); return handlesBinary.invokeClient(mimeType, reader, response.getStatus(), headers);
} finally { } finally {
IOUtils.closeQuietly(reader); IOUtils.closeQuietly(reader);
} }
} }
} }
Reader reader = createReaderFromResponse(response); Reader reader = response.createReader();
if (ourLog.isTraceEnabled() || myKeepResponses || theLogRequestAndResponse) { if (ourLog.isTraceEnabled() || myKeepResponses || theLogRequestAndResponse) {
String responseString = IOUtils.toString(reader); String responseString = IOUtils.toString(reader);
@ -355,22 +326,24 @@ public abstract class BaseClient implements IRestfulClient {
} }
try { try {
return binding.invokeClient(mimeType, reader, response.getStatusLine().getStatusCode(), headers); return binding.invokeClient(mimeType, reader, response.getStatus(), headers);
} finally { } finally {
IOUtils.closeQuietly(reader); IOUtils.closeQuietly(reader);
} }
} catch (DataFormatException e) {
throw new FhirClientConnectionException(e);
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
throw new FhirClientConnectionException(e); throw new FhirClientConnectionException(e);
} catch (IOException e) { } catch (IOException e) {
throw new FhirClientConnectionException(e); throw new FhirClientConnectionException(e);
} catch(RuntimeException e) {
throw e;
} catch (Exception e) {
throw new FhirClientConnectionException(e);
} finally { } finally {
if (response instanceof CloseableHttpResponse) { if (response != null) {
try { response.close();
((CloseableHttpResponse) response).close();
} catch (IOException e) {
ourLog.debug("Failed to close response", e);
}
} }
} }
} }
@ -391,13 +364,13 @@ public abstract class BaseClient implements IRestfulClient {
return Boolean.TRUE.equals(myPrettyPrint); return Boolean.TRUE.equals(myPrettyPrint);
} }
private void keepResponseAndLogIt(boolean theLogRequestAndResponse, HttpResponse response, String responseString) { private void keepResponseAndLogIt(boolean theLogRequestAndResponse, IHttpResponse response, String responseString) {
if (myKeepResponses) { if (myKeepResponses) {
myLastResponse = response; myLastResponse = response;
myLastResponseBody = responseString; myLastResponseBody = responseString;
} }
if (theLogRequestAndResponse) { if (theLogRequestAndResponse) {
String message = "HTTP " + response.getStatusLine().getStatusCode() + " " + response.getStatusLine().getReasonPhrase(); String message = "HTTP " + response.getStatus() + " " + response.getStatusInfo();
if (StringUtils.isNotBlank(responseString)) { if (StringUtils.isNotBlank(responseString)) {
ourLog.info("Client response: {}\n{}", message, responseString); ourLog.info("Client response: {}\n{}", message, responseString);
} else { } else {
@ -444,7 +417,7 @@ public abstract class BaseClient implements IRestfulClient {
/** /**
* For now, this is a part of the internal API of HAPI - Use with caution as this method may change! * For now, this is a part of the internal API of HAPI - Use with caution as this method may change!
*/ */
public void setLastResponse(HttpResponse theLastResponse) { public void setLastResponse(IHttpResponse theLastResponse) {
myLastResponse = theLastResponse; myLastResponse = theLastResponse;
} }
@ -477,30 +450,9 @@ public abstract class BaseClient implements IRestfulClient {
myInterceptors.remove(theInterceptor); myInterceptors.remove(theInterceptor);
} }
public static Reader createReaderFromResponse(HttpResponse theResponse) throws IllegalStateException, IOException {
HttpEntity entity = theResponse.getEntity();
if (entity == null) {
return new StringReader("");
}
Charset charset = null;
if (entity.getContentType() != null && entity.getContentType().getElements() != null && entity.getContentType().getElements().length > 0) {
ContentType ct = ContentType.get(entity);
charset = ct.getCharset();
}
if (charset == null) {
if (Constants.STATUS_HTTP_204_NO_CONTENT != theResponse.getStatusLine().getStatusCode()) {
ourLog.warn("Response did not specify a charset.");
}
charset = Charset.forName("UTF-8");
}
Reader reader = new InputStreamReader(theResponse.getEntity().getContent(), charset);
return reader;
}
@Override @Override
public <T extends IBaseResource> T fetchResourceFromUrl(Class<T> theResourceType, String theUrl) { public <T extends IBaseResource> T fetchResourceFromUrl(Class<T> theResourceType, String theUrl) {
BaseHttpClientInvocation clientInvocation = new HttpGetClientInvocation(theUrl); BaseHttpClientInvocation clientInvocation = new HttpGetClientInvocation(getFhirContext(), theUrl);
ResourceResponseHandler<T> binding = new ResourceResponseHandler<T>(theResourceType, null, false); ResourceResponseHandler<T> binding = new ResourceResponseHandler<T>(theResourceType, null, false);
return invokeClient(getFhirContext(), binding, clientInvocation, null, false, false, null, null); return invokeClient(getFhirContext(), binding, clientInvocation, null, false, false, null, null);
} }

View File

@ -27,23 +27,25 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import org.apache.http.Header; import ca.uhn.fhir.context.FhirContext;
import org.apache.http.client.methods.HttpRequestBase; import ca.uhn.fhir.rest.api.RequestTypeEnum;
import org.apache.http.message.BasicHeader; import ca.uhn.fhir.rest.client.api.Header;
import ca.uhn.fhir.rest.client.api.IHttpClient;
import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.client.api.IHttpRequest;
import ca.uhn.fhir.rest.server.EncodingEnum; import ca.uhn.fhir.rest.server.EncodingEnum;
import ca.uhn.fhir.util.VersionUtil;
public abstract class BaseHttpClientInvocation { public abstract class BaseHttpClientInvocation {
private List<Header> myHeaders; private final List<Header> myHeaders;
private final FhirContext myContext;
public BaseHttpClientInvocation(FhirContext myContext) {
this.myContext = myContext;
this.myHeaders = new ArrayList<Header>();
}
public void addHeader(String theName, String theValue) { public void addHeader(String theName, String theValue) {
if (myHeaders == null) { myHeaders.add(new Header(theName, theValue));
myHeaders = new ArrayList<Header>();
}
myHeaders.add(new BasicHeader(theName, theValue));
} }
/** /**
@ -57,15 +59,15 @@ public abstract class BaseHttpClientInvocation {
* The encoding to use for any serialized content sent to the * The encoding to use for any serialized content sent to the
* server * server
*/ */
public abstract HttpRequestBase asHttpRequest(String theUrlBase, Map<String, List<String>> theExtraParams, EncodingEnum theEncoding, Boolean thePrettyPrint); public abstract IHttpRequest asHttpRequest(String theUrlBase, Map<String, List<String>> theExtraParams, EncodingEnum theEncoding, Boolean thePrettyPrint);
protected static void appendExtraParamsWithQuestionMark(Map<String, List<String>> theExtraParams, StringBuilder theUrlBuilder, boolean theWithQuestionMark) { public static void appendExtraParamsWithQuestionMark(Map<String, List<String>> theExtraParams, StringBuilder theUrlBuilder, boolean theWithQuestionMark) {
if (theExtraParams == null) { if (theExtraParams == null) {
return; return;
} }
boolean first = theWithQuestionMark; boolean first = theWithQuestionMark;
if (theExtraParams != null && theExtraParams.isEmpty() == false) { if (theExtraParams.isEmpty() == false) {
for (Entry<String, List<String>> next : theExtraParams.entrySet()) { for (Entry<String, List<String>> next : theExtraParams.entrySet()) {
for (String nextValue : next.getValue()) { for (String nextValue : next.getValue()) {
if (first) { if (first) {
@ -86,25 +88,43 @@ public abstract class BaseHttpClientInvocation {
} }
} }
public void addHeadersToRequest(HttpRequestBase theHttpRequest, EncodingEnum theEncoding) { /**
if (myHeaders != null) { * Get the restfull client factory
for (Header next : myHeaders) { * @return
theHttpRequest.addHeader(next); */
} public IRestfulClientFactory getRestfulClientFactory() {
} return myContext.getRestfulClientFactory();
}
String versionString = VersionUtil.getVersion(); /**
theHttpRequest.addHeader("User-Agent", "HAPI-FHIR/" + versionString + " (FHIR Client)"); * Create an HTTP request for the given url, encoding and request-type
theHttpRequest.addHeader("Accept-Charset", "utf-8"); *
theHttpRequest.addHeader("Accept-Encoding", "gzip"); * @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(theEncoding);
}
if (theEncoding == null) { /**
theHttpRequest.addHeader(Constants.HEADER_ACCEPT, Constants.HEADER_ACCEPT_VALUE_XML_OR_JSON); * Returns the http headers to be sent with the request
} else if (theEncoding == EncodingEnum.JSON) { */
theHttpRequest.addHeader(Constants.HEADER_ACCEPT, Constants.CT_FHIR_JSON); public List<Header> getHeaders() {
} else if (theEncoding == EncodingEnum.XML) { return myHeaders;
theHttpRequest.addHeader(Constants.HEADER_ACCEPT, Constants.CT_FHIR_XML); }
}
/**
* Returns the FHIR context associated with this client
* @return the myContext
*/
public FhirContext getFhirContext() {
return myContext;
} }
} }

View File

@ -24,20 +24,19 @@ import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Map; import java.util.Map;
import org.apache.http.client.HttpClient;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.client.ClientInvocationHandlerFactory.ILambda; import ca.uhn.fhir.rest.client.ClientInvocationHandlerFactory.ILambda;
import ca.uhn.fhir.rest.client.api.IHttpClient;
import ca.uhn.fhir.rest.method.BaseMethodBinding; import ca.uhn.fhir.rest.method.BaseMethodBinding;
class ClientInvocationHandler extends BaseClient implements InvocationHandler { public class ClientInvocationHandler extends BaseClient implements InvocationHandler {
private final Map<Method, BaseMethodBinding<?>> myBindings; private final Map<Method, BaseMethodBinding<?>> myBindings;
private final Map<Method, Object> myMethodToReturnValue; private final Map<Method, Object> myMethodToReturnValue;
private FhirContext myContext; private FhirContext myContext;
private Map<Method, ILambda> myMethodToLambda; private Map<Method, ILambda> myMethodToLambda;
public ClientInvocationHandler(HttpClient theClient, FhirContext theContext, String theUrlBase, Map<Method, Object> theMethodToReturnValue, Map<Method, BaseMethodBinding<?>> theBindings, Map<Method, ILambda> theMethodToLambda, RestfulClientFactory theFactory) { public ClientInvocationHandler(IHttpClient theClient, FhirContext theContext, String theUrlBase, Map<Method, Object> theMethodToReturnValue, Map<Method, BaseMethodBinding<?>> theBindings, Map<Method, ILambda> theMethodToLambda, RestfulClientFactory theFactory) {
super(theClient, theUrlBase, theFactory); super(theClient, theUrlBase, theFactory);
myContext = theContext; myContext = theContext;

View File

@ -24,26 +24,26 @@ import java.lang.reflect.Method;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.apache.http.client.HttpClient;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.context.ConfigurationException; import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.api.SummaryEnum; import ca.uhn.fhir.rest.api.SummaryEnum;
import ca.uhn.fhir.rest.client.api.IHttpClient;
import ca.uhn.fhir.rest.client.api.IRestfulClient; import ca.uhn.fhir.rest.client.api.IRestfulClient;
import ca.uhn.fhir.rest.method.BaseMethodBinding; import ca.uhn.fhir.rest.method.BaseMethodBinding;
import ca.uhn.fhir.rest.server.EncodingEnum; import ca.uhn.fhir.rest.server.EncodingEnum;
class ClientInvocationHandlerFactory { public class ClientInvocationHandlerFactory {
private final Map<Method, BaseMethodBinding<?>> myBindings = new HashMap<Method, BaseMethodBinding<?>>(); private final Map<Method, BaseMethodBinding<?>> myBindings = new HashMap<Method, BaseMethodBinding<?>>();
private final HttpClient myClient; private final IHttpClient myClient;
private final FhirContext myContext; private final FhirContext myContext;
private final Map<Method, ILambda> myMethodToLambda = new HashMap<Method, ILambda>(); private final Map<Method, ILambda> myMethodToLambda = new HashMap<Method, ILambda>();
private final Map<Method, Object> myMethodToReturnValue = new HashMap<Method, Object>(); private final Map<Method, Object> myMethodToReturnValue = new HashMap<Method, Object>();
private final String myUrlBase; private final String myUrlBase;
public ClientInvocationHandlerFactory(HttpClient theClient, FhirContext theContext, String theUrlBase, Class<? extends IRestfulClient> theClientType) { public ClientInvocationHandlerFactory(IHttpClient theClient, FhirContext theContext, String theUrlBase, Class<? extends IRestfulClient> theClientType) {
myClient = theClient; myClient = theClient;
myUrlBase = theUrlBase; myUrlBase = theUrlBase;
myContext = theContext; myContext = theContext;
@ -75,7 +75,7 @@ class ClientInvocationHandlerFactory {
return new ClientInvocationHandler(myClient, myContext, myUrlBase, myMethodToReturnValue, myBindings, myMethodToLambda, theRestfulClientFactory); return new ClientInvocationHandler(myClient, myContext, myUrlBase, myMethodToReturnValue, myBindings, myMethodToLambda, theRestfulClientFactory);
} }
interface ILambda { public interface ILambda {
Object handle(ClientInvocationHandler theTarget, Object[] theArgs); Object handle(ClientInvocationHandler theTarget, Object[] theArgs);
} }

View File

@ -38,8 +38,6 @@ import java.util.Set;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.Validate;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpRequestBase;
import org.hl7.fhir.instance.model.api.IBase; import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseBundle; import org.hl7.fhir.instance.model.api.IBaseBundle;
import org.hl7.fhir.instance.model.api.IBaseConformance; import org.hl7.fhir.instance.model.api.IBaseConformance;
@ -72,6 +70,8 @@ import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.api.MethodOutcome; import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.PreferReturnEnum; import ca.uhn.fhir.rest.api.PreferReturnEnum;
import ca.uhn.fhir.rest.api.SummaryEnum; import ca.uhn.fhir.rest.api.SummaryEnum;
import ca.uhn.fhir.rest.client.api.IHttpClient;
import ca.uhn.fhir.rest.client.api.IHttpRequest;
import ca.uhn.fhir.rest.client.exceptions.NonFhirResponseException; import ca.uhn.fhir.rest.client.exceptions.NonFhirResponseException;
import ca.uhn.fhir.rest.gclient.IClientExecutable; import ca.uhn.fhir.rest.gclient.IClientExecutable;
import ca.uhn.fhir.rest.gclient.ICreate; import ca.uhn.fhir.rest.gclient.ICreate;
@ -157,13 +157,13 @@ public class GenericClient extends BaseClient implements IGenericClient {
private static final String I18N_NO_VERSION_ID_FOR_VREAD = "ca.uhn.fhir.rest.client.GenericClient.noVersionIdForVread"; private static final String I18N_NO_VERSION_ID_FOR_VREAD = "ca.uhn.fhir.rest.client.GenericClient.noVersionIdForVread";
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(GenericClient.class); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(GenericClient.class);
private FhirContext myContext; private FhirContext myContext;
private HttpRequestBase myLastRequest; private IHttpRequest myLastRequest;
private boolean myLogRequestAndResponse; private boolean myLogRequestAndResponse;
/** /**
* For now, this is a part of the internal API of HAPI - Use with caution as this method may change! * For now, this is a part of the internal API of HAPI - Use with caution as this method may change!
*/ */
public GenericClient(FhirContext theContext, HttpClient theHttpClient, String theServerBase, RestfulClientFactory theFactory) { public GenericClient(FhirContext theContext, IHttpClient theHttpClient, String theServerBase, RestfulClientFactory theFactory) {
super(theHttpClient, theServerBase, theFactory); super(theHttpClient, theServerBase, theFactory);
myContext = theContext; myContext = theContext;
} }
@ -174,7 +174,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
throw new IllegalArgumentException("Must call conformance(" + IBaseConformance.class.getSimpleName() + ") instead of conformance() for HL7.org structures"); throw new IllegalArgumentException("Must call conformance(" + IBaseConformance.class.getSimpleName() + ") instead of conformance() for HL7.org structures");
} }
HttpGetClientInvocation invocation = MethodUtil.createConformanceInvocation(); HttpGetClientInvocation invocation = MethodUtil.createConformanceInvocation(getFhirContext());
if (isKeepResponses()) { if (isKeepResponses()) {
myLastRequest = invocation.asHttpRequest(getServerBase(), createExtraParams(), getEncoding(), isPrettyPrint()); myLastRequest = invocation.asHttpRequest(getServerBase(), createExtraParams(), getEncoding(), isPrettyPrint());
} }
@ -216,7 +216,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
@Override @Override
public MethodOutcome delete(final Class<? extends IBaseResource> theType, IdDt theId) { public MethodOutcome delete(final Class<? extends IBaseResource> theType, IdDt theId) {
HttpDeleteClientInvocation invocation = DeleteMethodBinding.createDeleteInvocation(theId.withResourceType(toResourceName(theType))); HttpDeleteClientInvocation invocation = DeleteMethodBinding.createDeleteInvocation(getFhirContext(), theId.withResourceType(toResourceName(theType)));
if (isKeepResponses()) { if (isKeepResponses()) {
myLastRequest = invocation.asHttpRequest(getServerBase(), createExtraParams(), getEncoding(), isPrettyPrint()); myLastRequest = invocation.asHttpRequest(getServerBase(), createExtraParams(), getEncoding(), isPrettyPrint());
} }
@ -243,15 +243,15 @@ public class GenericClient extends BaseClient implements IGenericClient {
HttpGetClientInvocation invocation; HttpGetClientInvocation invocation;
if (id.hasBaseUrl()) { if (id.hasBaseUrl()) {
if (theVRead) { if (theVRead) {
invocation = ReadMethodBinding.createAbsoluteVReadInvocation(id); invocation = ReadMethodBinding.createAbsoluteVReadInvocation(getFhirContext(), id);
} else { } else {
invocation = ReadMethodBinding.createAbsoluteReadInvocation(id); invocation = ReadMethodBinding.createAbsoluteReadInvocation(getFhirContext(), id);
} }
} else { } else {
if (theVRead) { if (theVRead) {
invocation = ReadMethodBinding.createVReadInvocation(id, resName); invocation = ReadMethodBinding.createVReadInvocation(getFhirContext(), id, resName);
} else { } else {
invocation = ReadMethodBinding.createReadInvocation(id, resName); invocation = ReadMethodBinding.createReadInvocation(getFhirContext(), id, resName);
} }
} }
if (isKeepResponses()) { if (isKeepResponses()) {
@ -305,7 +305,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
return myContext; return myContext;
} }
public HttpRequestBase getLastRequest() { public IHttpRequest getLastRequest() {
return myLastRequest; return myLastRequest;
} }
@ -330,7 +330,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
public <T extends IBaseResource> Bundle history(final Class<T> theType, IdDt theIdDt, DateTimeDt theSince, Integer theLimit) { public <T extends IBaseResource> Bundle history(final Class<T> theType, IdDt theIdDt, DateTimeDt theSince, Integer theLimit) {
String resourceName = theType != null ? toResourceName(theType) : null; String resourceName = theType != null ? toResourceName(theType) : null;
String id = theIdDt != null && theIdDt.isEmpty() == false ? theIdDt.getValue() : null; String id = theIdDt != null && theIdDt.isEmpty() == false ? theIdDt.getValue() : null;
HttpGetClientInvocation invocation = HistoryMethodBinding.createHistoryInvocation(resourceName, id, theSince, theLimit); HttpGetClientInvocation invocation = HistoryMethodBinding.createHistoryInvocation(myContext, resourceName, id, theSince, theLimit);
if (isKeepResponses()) { if (isKeepResponses()) {
myLastRequest = invocation.asHttpRequest(getServerBase(), createExtraParams(), getEncoding(), isPrettyPrint()); myLastRequest = invocation.asHttpRequest(getServerBase(), createExtraParams(), getEncoding(), isPrettyPrint());
} }
@ -468,7 +468,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
@Override @Override
public <T extends IBaseResource> Bundle search(final Class<T> theType, UriDt theUrl) { public <T extends IBaseResource> Bundle search(final Class<T> theType, UriDt theUrl) {
BaseHttpClientInvocation invocation = new HttpGetClientInvocation(theUrl.getValueAsString()); BaseHttpClientInvocation invocation = new HttpGetClientInvocation(getFhirContext(), theUrl.getValueAsString());
return invokeClient(myContext, new BundleResponseHandler(theType), invocation); return invokeClient(myContext, new BundleResponseHandler(theType), invocation);
} }
@ -480,7 +480,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
/** /**
* For now, this is a part of the internal API of HAPI - Use with caution as this method may change! * For now, this is a part of the internal API of HAPI - Use with caution as this method may change!
*/ */
public void setLastRequest(HttpRequestBase theLastRequest) { public void setLastRequest(IHttpRequest theLastRequest) {
myLastRequest = theLastRequest; myLastRequest = theLastRequest;
} }
@ -839,12 +839,12 @@ public class GenericClient extends BaseClient implements IGenericClient {
public BaseOperationOutcome execute() { public BaseOperationOutcome execute() {
HttpDeleteClientInvocation invocation; HttpDeleteClientInvocation invocation;
if (myId != null) { if (myId != null) {
invocation = DeleteMethodBinding.createDeleteInvocation(myId); invocation = DeleteMethodBinding.createDeleteInvocation(getFhirContext(), myId);
} else if (myCriterionList != null) { } else if (myCriterionList != null) {
Map<String, List<String>> params = myCriterionList.toParamList(); Map<String, List<String>> params = myCriterionList.toParamList();
invocation = DeleteMethodBinding.createDeleteInvocation(myResourceType, params); invocation = DeleteMethodBinding.createDeleteInvocation(getFhirContext(), myResourceType, params);
} else { } else {
invocation = DeleteMethodBinding.createDeleteInvocation(mySearchUrl); invocation = DeleteMethodBinding.createDeleteInvocation(getFhirContext(), mySearchUrl);
} }
OperationOutcomeResponseHandler binding = new OperationOutcomeResponseHandler(); OperationOutcomeResponseHandler binding = new OperationOutcomeResponseHandler();
Map<String, List<String>> params = new HashMap<String, List<String>>(); Map<String, List<String>> params = new HashMap<String, List<String>>();
@ -926,7 +926,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
@Override @Override
public Object execute() { public Object execute() {
ResourceResponseHandler binding = new ResourceResponseHandler(myType.getImplementingClass(), null); ResourceResponseHandler binding = new ResourceResponseHandler(myType.getImplementingClass(), null);
HttpGetClientInvocation invocation = MethodUtil.createConformanceInvocation(); HttpGetClientInvocation invocation = MethodUtil.createConformanceInvocation(getFhirContext());
return super.invoke(null, binding, invocation); return super.invoke(null, binding, invocation);
} }
@ -965,7 +965,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
} else { } else {
binding = new ResourceResponseHandler(myBundleType, null); binding = new ResourceResponseHandler(myBundleType, null);
} }
HttpSimpleGetClientInvocation invocation = new HttpSimpleGetClientInvocation(myUrl); HttpSimpleGetClientInvocation invocation = new HttpSimpleGetClientInvocation(myContext, myUrl);
Map<String, List<String>> params = null; Map<String, List<String>> params = null;
return invoke(params, binding, invocation); return invoke(params, binding, invocation);
@ -1002,7 +1002,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
} }
urlFragments.add(Constants.PARAM_TAGS); urlFragments.add(Constants.PARAM_TAGS);
HttpGetClientInvocation invocation = new HttpGetClientInvocation(params, urlFragments); HttpGetClientInvocation invocation = new HttpGetClientInvocation(myContext, params, urlFragments);
return invoke(params, binding, invocation); return invoke(params, binding, invocation);
@ -1083,7 +1083,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
id = null; id = null;
} }
HttpGetClientInvocation invocation = HistoryMethodBinding.createHistoryInvocation(resourceName, id, mySince, myCount); HttpGetClientInvocation invocation = HistoryMethodBinding.createHistoryInvocation(myContext, resourceName, id, mySince, myCount);
IClientResponseHandler handler; IClientResponseHandler handler;
if (myReturnType != null) { if (myReturnType != null) {
@ -1813,7 +1813,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
BaseHttpClientInvocation invocation; BaseHttpClientInvocation invocation;
if (mySearchUrl != null) { if (mySearchUrl != null) {
invocation = SearchMethodBinding.createSearchInvocation(mySearchUrl, params); invocation = SearchMethodBinding.createSearchInvocation(myContext, mySearchUrl, params);
} else { } else {
invocation = SearchMethodBinding.createSearchInvocation(myContext, myResourceName, params, resourceId, myCompartmentName, mySearchStyle); invocation = SearchMethodBinding.createSearchInvocation(myContext, myResourceName, params, resourceId, myCompartmentName, mySearchStyle);
} }

View File

@ -22,19 +22,19 @@ package ca.uhn.fhir.rest.client;
import java.io.IOException; import java.io.IOException;
import org.apache.http.HttpResponse; import ca.uhn.fhir.rest.client.api.IHttpRequest;
import org.apache.http.client.methods.HttpRequestBase; import ca.uhn.fhir.rest.client.api.IHttpResponse;
public interface IClientInterceptor { public interface IClientInterceptor {
/** /**
* Fired by the client just before invoking the HTTP client request * Fired by the client just before invoking the HTTP client request
*/ */
void interceptRequest(HttpRequestBase theRequest); void interceptRequest(IHttpRequest theRequest);
/** /**
* Fired by the client upon receiving an HTTP response, prior to processing that response * Fired by the client upon receiving an HTTP response, prior to processing that response
*/ */
void interceptResponse(HttpResponse theResponse) throws IOException; void interceptResponse(IHttpResponse theResponse) throws IOException;
} }

View File

@ -20,9 +20,13 @@ package ca.uhn.fhir.rest.client;
* #L% * #L%
*/ */
import org.apache.http.client.HttpClient; import java.util.List;
import java.util.Map;
import ca.uhn.fhir.context.ConfigurationException; import ca.uhn.fhir.context.ConfigurationException;
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.IRestfulClient; import ca.uhn.fhir.rest.client.api.IRestfulClient;
public interface IRestfulClientFactory { public interface IRestfulClientFactory {
@ -76,11 +80,20 @@ public interface IRestfulClientFactory {
int getConnectTimeout(); int getConnectTimeout();
/** /**
* Returns the Apache HTTP client instance. This method will not return null. * Returns the HTTP client instance. This method will not return null.
* * @param theUrl
* @see #setHttpClient(HttpClient) * The complete FHIR url to which the http request will be sent
* @param theIfNoneExistParams
* The params for header "If-None-Exist" as a hashmap
* @param theIfNoneExistString
* The param for header "If-None-Exist" as a string
* @param theRequestType
* the type of HTTP request (GET, DELETE, ..)
* @param theHeaders
* the headers to be sent together with the http request
* @return the HTTP client instance
*/ */
HttpClient getHttpClient(); IHttpClient getHttpClient(StringBuilder theUrl, Map<String, List<String>> theIfNoneExistParams, String theIfNoneExistString, RequestTypeEnum theRequestType, List<Header> theHeaders);
/** /**
* @deprecated Use {@link #getServerValidationMode()} instead * @deprecated Use {@link #getServerValidationMode()} instead
@ -172,7 +185,7 @@ public interface IRestfulClientFactory {
* @param theHttpClient * @param theHttpClient
* An HTTP client instance to use, or <code>null</code> * An HTTP client instance to use, or <code>null</code>
*/ */
void setHttpClient(HttpClient theHttpClient); <T> void setHttpClient(T theHttpClient);
/** /**
* Sets the HTTP proxy to use for outgoing connections * Sets the HTTP proxy to use for outgoing connections
@ -234,4 +247,12 @@ public interface IRestfulClientFactory {
* </p> * </p>
*/ */
void setPoolMaxPerRoute(int thePoolMaxPerRoute); void setPoolMaxPerRoute(int thePoolMaxPerRoute);
void validateServerBase(String theServerBase, IHttpClient theHttpClient, BaseClient theClient);
/**
* This method is internal to HAPI - It may change in future versions, use with caution.
*/
void validateServerBaseIfConfiguredToDoSo(String theServerBase, IHttpClient theHttpClient, BaseClient theClient);
} }

View File

@ -28,27 +28,16 @@ import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.Validate;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.client.ProxyAuthenticationStrategy;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IPrimitiveType; import org.hl7.fhir.instance.model.api.IPrimitiveType;
import ca.uhn.fhir.context.ConfigurationException; import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum; import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.rest.client.api.IHttpClient;
import ca.uhn.fhir.rest.client.api.IRestfulClient; import ca.uhn.fhir.rest.client.api.IRestfulClient;
import ca.uhn.fhir.rest.client.exceptions.FhirClientConnectionException; import ca.uhn.fhir.rest.client.exceptions.FhirClientConnectionException;
import ca.uhn.fhir.rest.client.exceptions.FhirClientInappropriateForServerException; import ca.uhn.fhir.rest.client.exceptions.FhirClientInappropriateForServerException;
@ -56,18 +45,18 @@ import ca.uhn.fhir.rest.method.BaseMethodBinding;
import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.util.FhirTerser; import ca.uhn.fhir.util.FhirTerser;
public class RestfulClientFactory implements IRestfulClientFactory { public abstract class RestfulClientFactory implements IRestfulClientFactory {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RestfulClientFactory.class); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RestfulClientFactory.class);
private int myConnectionRequestTimeout = DEFAULT_CONNECTION_REQUEST_TIMEOUT; private int myConnectionRequestTimeout = DEFAULT_CONNECTION_REQUEST_TIMEOUT;
private int myConnectTimeout = DEFAULT_CONNECT_TIMEOUT; private int myConnectTimeout = DEFAULT_CONNECT_TIMEOUT;
private FhirContext myContext; private FhirContext myContext;
private HttpClient myHttpClient;
private Map<Class<? extends IRestfulClient>, ClientInvocationHandlerFactory> myInvocationHandlers = new HashMap<Class<? extends IRestfulClient>, ClientInvocationHandlerFactory>(); private Map<Class<? extends IRestfulClient>, ClientInvocationHandlerFactory> myInvocationHandlers = new HashMap<Class<? extends IRestfulClient>, ClientInvocationHandlerFactory>();
private HttpHost myProxy;
private ServerValidationModeEnum myServerValidationMode = DEFAULT_SERVER_VALIDATION_MODE; private ServerValidationModeEnum myServerValidationMode = DEFAULT_SERVER_VALIDATION_MODE;
private int mySocketTimeout = DEFAULT_SOCKET_TIMEOUT; private int mySocketTimeout = DEFAULT_SOCKET_TIMEOUT;
private Set<String> myValidatedServerBaseUrls = Collections.synchronizedSet(new HashSet<String>()); private Set<String> myValidatedServerBaseUrls = Collections.synchronizedSet(new HashSet<String>());
private String myProxyUsername;
private String myProxyPassword;
private int myPoolMaxTotal = DEFAULT_POOL_MAX; private int myPoolMaxTotal = DEFAULT_POOL_MAX;
private int myPoolMaxPerRoute = DEFAULT_POOL_MAX_PER_ROUTE; private int myPoolMaxPerRoute = DEFAULT_POOL_MAX_PER_ROUTE;
@ -97,45 +86,21 @@ public class RestfulClientFactory implements IRestfulClientFactory {
return myConnectTimeout; return myConnectTimeout;
} }
@Override /**
public synchronized HttpClient getHttpClient() { * Return the proxy username to authenticate with the HTTP proxy
if (myHttpClient == null) { * @param The proxy username
*/
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS); protected String getProxyUsername() {
connectionManager.setMaxTotal(myPoolMaxTotal); return myProxyUsername;
connectionManager.setDefaultMaxPerRoute(myPoolMaxPerRoute);
//@formatter:off
RequestConfig defaultRequestConfig = RequestConfig.custom()
.setSocketTimeout(mySocketTimeout)
.setConnectTimeout(myConnectTimeout)
.setConnectionRequestTimeout(myConnectionRequestTimeout)
.setStaleConnectionCheckEnabled(true)
.setProxy(myProxy)
.build();
HttpClientBuilder builder = HttpClients.custom()
.setConnectionManager(connectionManager)
.setDefaultRequestConfig(defaultRequestConfig)
.disableCookieManagement();
if (myProxy != null && StringUtils.isNotBlank(myProxyUsername) && StringUtils.isNotBlank(myProxyPassword)) {
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(new AuthScope(myProxy.getHostName(), myProxy.getPort()), new UsernamePasswordCredentials(myProxyUsername, myProxyPassword));
builder.setProxyAuthenticationStrategy(new ProxyAuthenticationStrategy());
builder.setDefaultCredentialsProvider(credsProvider);
}
myHttpClient = builder.build();
//@formatter:on
}
return myHttpClient;
} }
private String myProxyUsername; /**
private String myProxyPassword; * Return the proxy password to authenticate with the HTTP proxy
* @param The proxy password
*/
protected String getProxyPassword() {
return myProxyPassword;
}
@Override @Override
public void setProxyCredentials(String theUsername, String thePassword) { public void setProxyCredentials(String theUsername, String thePassword) {
@ -189,7 +154,7 @@ public class RestfulClientFactory implements IRestfulClientFactory {
ClientInvocationHandlerFactory invocationHandler = myInvocationHandlers.get(theClientType); ClientInvocationHandlerFactory invocationHandler = myInvocationHandlers.get(theClientType);
if (invocationHandler == null) { if (invocationHandler == null) {
HttpClient httpClient = getHttpClient(); IHttpClient httpClient = getHttpClient(theServerBase);
invocationHandler = new ClientInvocationHandlerFactory(httpClient, myContext, theServerBase, theClientType); invocationHandler = new ClientInvocationHandlerFactory(httpClient, myContext, theServerBase, theClientType);
for (Method nextMethod : theClientType.getMethods()) { for (Method nextMethod : theClientType.getMethods()) {
BaseMethodBinding<?> binding = BaseMethodBinding.bindMethod(nextMethod, myContext, null); BaseMethodBinding<?> binding = BaseMethodBinding.bindMethod(nextMethod, myContext, null);
@ -205,14 +170,12 @@ public class RestfulClientFactory implements IRestfulClientFactory {
@Override @Override
public synchronized IGenericClient newGenericClient(String theServerBase) { public synchronized IGenericClient newGenericClient(String theServerBase) {
HttpClient httpClient = getHttpClient(); IHttpClient httpClient = getHttpClient(theServerBase);
return new GenericClient(myContext, httpClient, theServerBase, this); return new GenericClient(myContext, httpClient, theServerBase, this);
} }
/** @Override
* This method is internal to HAPI - It may change in future versions, use with caution. public void validateServerBaseIfConfiguredToDoSo(String theServerBase, IHttpClient theHttpClient, BaseClient theClient) {
*/
public void validateServerBaseIfConfiguredToDoSo(String theServerBase, HttpClient theHttpClient, BaseClient theClient) {
String serverBase = normalizeBaseUrlForMap(theServerBase); String serverBase = normalizeBaseUrlForMap(theServerBase);
switch (myServerValidationMode) { switch (myServerValidationMode) {
@ -238,13 +201,13 @@ public class RestfulClientFactory implements IRestfulClientFactory {
@Override @Override
public synchronized void setConnectionRequestTimeout(int theConnectionRequestTimeout) { public synchronized void setConnectionRequestTimeout(int theConnectionRequestTimeout) {
myConnectionRequestTimeout = theConnectionRequestTimeout; myConnectionRequestTimeout = theConnectionRequestTimeout;
myHttpClient = null; resetHttpClient();
} }
@Override @Override
public synchronized void setConnectTimeout(int theConnectTimeout) { public synchronized void setConnectTimeout(int theConnectTimeout) {
myConnectTimeout = theConnectTimeout; myConnectTimeout = theConnectTimeout;
myHttpClient = null; resetHttpClient();
} }
/** /**
@ -258,24 +221,11 @@ public class RestfulClientFactory implements IRestfulClientFactory {
} }
/** /**
* Sets the Apache HTTP client instance to be used by any new restful clients created by this factory. If set to * Return the fhir context
* <code>null</code>, which is the default, a new HTTP client with default settings will be created. * @return the fhir context
*
* @param theHttpClient
* An HTTP client instance to use, or <code>null</code>
*/ */
@Override public FhirContext getFhirContext() {
public synchronized void setHttpClient(HttpClient theHttpClient) { return myContext;
myHttpClient = theHttpClient;
}
@Override
public void setProxy(String theHost, Integer thePort) {
if (theHost != null) {
myProxy = new HttpHost(theHost, thePort, "http");
} else {
myProxy = null;
}
} }
@Override @Override
@ -287,24 +237,39 @@ public class RestfulClientFactory implements IRestfulClientFactory {
@Override @Override
public synchronized void setSocketTimeout(int theSocketTimeout) { public synchronized void setSocketTimeout(int theSocketTimeout) {
mySocketTimeout = theSocketTimeout; mySocketTimeout = theSocketTimeout;
myHttpClient = null; resetHttpClient();
} }
@Override @Override
public synchronized void setPoolMaxTotal(int thePoolMaxTotal) { public synchronized void setPoolMaxTotal(int thePoolMaxTotal) {
myPoolMaxTotal = thePoolMaxTotal; myPoolMaxTotal = thePoolMaxTotal;
myHttpClient = null; resetHttpClient();
} }
@Override @Override
public synchronized void setPoolMaxPerRoute(int thePoolMaxPerRoute) { public synchronized void setPoolMaxPerRoute(int thePoolMaxPerRoute) {
myPoolMaxPerRoute = thePoolMaxPerRoute; myPoolMaxPerRoute = thePoolMaxPerRoute;
myHttpClient = null; resetHttpClient();
} }
@SuppressWarnings("unchecked") /**
void validateServerBase(String theServerBase, HttpClient theHttpClient, BaseClient theClient) { * Instantiates a new client invocation handler
* @param theClient
* the client which will invoke the call
* @param theUrlBase
* the url base
* @param theMethodToReturnValue
* @param theBindings
* @param theMethodToLambda
* @return a newly created client invocation handler
*/
ClientInvocationHandler newInvocationHandler(IHttpClient theClient, String theUrlBase, Map<Method, Object> theMethodToReturnValue, Map<Method, BaseMethodBinding<?>> theBindings, Map<Method, ClientInvocationHandlerFactory.ILambda> theMethodToLambda) {
return new ClientInvocationHandler(theClient, getFhirContext(), theUrlBase.toString(), theMethodToReturnValue,
theBindings, theMethodToLambda, this);
}
@Override
public void validateServerBase(String theServerBase, IHttpClient theHttpClient, BaseClient theClient) {
GenericClient client = new GenericClient(myContext, theHttpClient, theServerBase, this); GenericClient client = new GenericClient(myContext, theHttpClient, theServerBase, this);
client.setEncoding(theClient.getEncoding()); client.setEncoding(theClient.getEncoding());
for (IClientInterceptor interceptor : theClient.getInterceptors()) { for (IClientInterceptor interceptor : theClient.getInterceptors()) {
@ -364,4 +329,17 @@ public class RestfulClientFactory implements IRestfulClientFactory {
setServerValidationMode(theServerValidationMode); setServerValidationMode(theServerValidationMode);
} }
/**
* Get the http client for the given server base
* @param theServerBase the server base
* @return the http client
*/
protected abstract IHttpClient getHttpClient(String theServerBase);
/**
* Reset the http client. This method is used when parameters have been set and a
* new http client needs to be created
*/
protected abstract void resetHttpClient();
} }

View File

@ -0,0 +1,202 @@
package ca.uhn.fhir.rest.client.apache;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2016 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpOptions;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.message.BasicNameValuePair;
import org.hl7.fhir.instance.model.api.IBaseBinary;
import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.client.BaseHttpClientInvocation;
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.server.Constants;
import ca.uhn.fhir.rest.server.EncodingEnum;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.util.VersionUtil;
/**
* A Http Client based on Apache. This is an adapter around the class
* {@link org.apache.http.client.HttpClient HttpClient}
*
* @author Peter Van Houte | peter.vanhoute@agfa.com | Agfa Healthcare
*/
public class ApacheHttpClient implements IHttpClient {
private HttpClient myClient;
private List<Header> myHeaders;
private StringBuilder myUrl;
private Map<String, List<String>> myIfNoneExistParams;
private String myIfNoneExistString;
private RequestTypeEnum myRequestType;
public ApacheHttpClient(HttpClient theClient, StringBuilder theUrl, Map<String, List<String>> theIfNoneExistParams,
String theIfNoneExistString, RequestTypeEnum theRequestType, List<Header> theHeaders) {
this.myClient = theClient;
this.myUrl = theUrl;
this.myIfNoneExistParams = theIfNoneExistParams;
this.myIfNoneExistString = theIfNoneExistString;
this.myRequestType = theRequestType;
this.myHeaders = theHeaders;
}
@Override
public IHttpRequest createByteRequest(String theContents, String theContentType, EncodingEnum theEncoding) {
/*
* We aren't using a StringEntity here because the constructors
* supported by Android aren't available in non-Android, and vice versa.
* Since we add the content type header manually, it makes no difference
* which one we use anyhow.
*/
ByteArrayEntity entity = new ByteArrayEntity(theContents.getBytes(Constants.CHARSET_UTF8));
ApacheHttpRequest retVal = createHttpRequest(entity);
addHeadersToRequest(retVal, theEncoding);
retVal.addHeader(Constants.HEADER_CONTENT_TYPE, theContentType + Constants.HEADER_SUFFIX_CT_UTF_8);
return retVal;
}
@Override
public IHttpRequest createParamRequest(Map<String, List<String>> theParams, EncodingEnum theEncoding) {
List<NameValuePair> parameters = new ArrayList<NameValuePair>();
for (Entry<String, List<String>> nextParam : theParams.entrySet()) {
List<String> value = nextParam.getValue();
for (String s : value) {
parameters.add(new BasicNameValuePair(nextParam.getKey(), s));
}
}
try {
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(parameters, "UTF-8");
return createHttpRequest(entity);
} catch (UnsupportedEncodingException e) {
throw new InternalErrorException("Server does not support UTF-8 (should not happen)", e);
}
}
@Override
public IHttpRequest createBinaryRequest(IBaseBinary theBinary) {
/*
* Note: Be careful about changing which constructor we use for
* ByteArrayEntity, as Android's version of HTTPClient doesn't support
* the newer ones for whatever reason.
*/
ByteArrayEntity entity = new ByteArrayEntity(theBinary.getContent());
entity.setContentType(theBinary.getContentType());
return createHttpRequest(entity);
}
@Override
public IHttpRequest createGetRequest(EncodingEnum theEncoding) {
ApacheHttpRequest retVal = createHttpRequest(null);
addHeadersToRequest(retVal, theEncoding);
return retVal;
}
public void addHeadersToRequest(ApacheHttpRequest theHttpRequest, EncodingEnum theEncoding) {
if (myHeaders != null) {
for (Header next : myHeaders) {
theHttpRequest.addHeader(next.getName(), next.getValue());
}
}
theHttpRequest.addHeader("User-Agent", "HAPI-FHIR/" + VersionUtil.getVersion() + " (FHIR Client)");
theHttpRequest.addHeader("Accept-Charset", "utf-8");
theHttpRequest.addHeader("Accept-Encoding", "gzip");
if (theEncoding == null) {
theHttpRequest.addHeader(Constants.HEADER_ACCEPT, Constants.HEADER_ACCEPT_VALUE_ALL);
} else if (theEncoding == EncodingEnum.JSON) {
theHttpRequest.addHeader(Constants.HEADER_ACCEPT, Constants.CT_FHIR_JSON);
} else if (theEncoding == EncodingEnum.XML) {
theHttpRequest.addHeader(Constants.HEADER_ACCEPT, Constants.CT_FHIR_XML);
}
}
private ApacheHttpRequest createHttpRequest(HttpEntity theEntity) {
HttpRequestBase request = constructRequestBase(theEntity);
ApacheHttpRequest result = new ApacheHttpRequest(myClient, request);
addHeaderIfNoneExist(result);
return result;
}
private void addHeaderIfNoneExist(IHttpRequest result) {
if (myIfNoneExistParams != null) {
StringBuilder b = newHeaderBuilder(myUrl);
BaseHttpClientInvocation.appendExtraParamsWithQuestionMark(myIfNoneExistParams, b, b.indexOf("?") == -1);
result.addHeader(Constants.HEADER_IF_NONE_EXIST, b.toString());
}
if (myIfNoneExistString != null) {
StringBuilder b = newHeaderBuilder(myUrl);
b.append(b.indexOf("?") == -1 ? '?' : '&');
b.append(myIfNoneExistString.substring(myIfNoneExistString.indexOf('?') + 1));
result.addHeader(Constants.HEADER_IF_NONE_EXIST, b.toString());
}
}
private StringBuilder newHeaderBuilder(StringBuilder theUrlBase) {
StringBuilder b = new StringBuilder();
b.append(theUrlBase);
if (theUrlBase.length() > 0 && theUrlBase.charAt(theUrlBase.length() - 1) == '/') {
b.deleteCharAt(b.length() - 1);
}
return b;
}
private HttpRequestBase constructRequestBase(HttpEntity theEntity) {
String url = myUrl.toString();
switch (myRequestType) {
case DELETE:
return new HttpDelete(url);
case OPTIONS:
return new HttpOptions(url);
case POST:
HttpPost httpPost = new HttpPost(url);
httpPost.setEntity(theEntity);
return httpPost;
case PUT:
HttpPut httpPut = new HttpPut(url);
httpPut.setEntity(theEntity);
return httpPut;
case GET:
default:
return new HttpGet(url);
}
}
}

View File

@ -0,0 +1,101 @@
package ca.uhn.fhir.rest.client.apache;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2016 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.apache.commons.io.IOUtils;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpRequestBase;
import ca.uhn.fhir.rest.client.api.IHttpRequest;
import ca.uhn.fhir.rest.client.api.IHttpResponse;
/**
* A Http Request based on Apache. This is an adapter around the class
* {@link org.apache.http.client.methods.HttpRequestBase HttpRequestBase}
*
* @author Peter Van Houte | peter.vanhoute@agfa.com | Agfa Healthcare
*/
public class ApacheHttpRequest implements IHttpRequest {
private HttpRequestBase myRequest;
private HttpClient myClient;
public ApacheHttpRequest(HttpClient theClient, HttpRequestBase theApacheRequest) {
this.myClient = theClient;
this.myRequest = theApacheRequest;
}
@Override
public void addHeader(String theName, String theValue) {
myRequest.addHeader(theName, theValue);
}
/**
* Get the ApacheRequest
* @return the ApacheRequest
*/
public HttpRequestBase getApacheRequest() {
return myRequest;
}
@Override
public IHttpResponse execute() throws IOException {
return new ApacheHttpResponse(myClient.execute(myRequest));
}
@Override
public Map<String, List<String>> getAllHeaders() {
Map<String, List<String>> result = new HashMap<String, List<String>>();
for (Header header : myRequest.getAllHeaders()) {
if (!result.containsKey(header.getName())) {
result.put(header.getName(), new LinkedList<String>());
}
result.get(header.getName()).add(header.getValue());
}
return result;
}
@Override
public String toString() {
return myRequest.toString();
}
@Override
public String getRequestBodyFromStream() throws IOException {
if (myRequest instanceof HttpEntityEnclosingRequest) {
HttpEntity entity = ((HttpEntityEnclosingRequest) myRequest).getEntity();
if (entity.isRepeatable()) {
return IOUtils.toString(entity.getContent());
}
}
return null;
}
}

View File

@ -0,0 +1,163 @@
package ca.uhn.fhir.rest.client.apache;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2016 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.io.IOUtils;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.entity.ContentType;
import ca.uhn.fhir.rest.client.api.IHttpResponse;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
/**
* A Http Response based on Apache. This is an adapter around the class
* {@link org.apache.http.HttpResponse HttpResponse}
*
* @author Peter Van Houte | peter.vanhoute@agfa.com | Agfa Healthcare
*/
public class ApacheHttpResponse implements IHttpResponse {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ApacheHttpResponse.class);
private boolean myEntityBuffered = false;
private final HttpResponse myResponse;
private byte[] myEntityBytes;
public ApacheHttpResponse(HttpResponse theResponse) {
this.myResponse = theResponse;
}
@Override
public HttpResponse getResponse() {
return myResponse;
}
@Override
public int getStatus() {
return myResponse.getStatusLine().getStatusCode();
}
@Override
public String getMimeType() {
ContentType ct = ContentType.get(myResponse.getEntity());
return ct != null ? ct.getMimeType() : null;
}
@Override
public Map<String, List<String>> getAllHeaders() {
Map<String, List<String>> headers = new HashMap<String, List<String>>();
if (myResponse.getAllHeaders() != null) {
for (Header next : myResponse.getAllHeaders()) {
String name = next.getName().toLowerCase();
List<String> list = headers.get(name);
if (list == null) {
list = new ArrayList<String>();
headers.put(name, list);
}
list.add(next.getValue());
}
}
return headers;
}
@Override
public String getStatusInfo() {
return myResponse.getStatusLine().getReasonPhrase();
}
@Override
public Reader createReader() throws IOException {
HttpEntity entity = myResponse.getEntity();
if (entity == null) {
return new StringReader("");
}
Charset charset = null;
if (entity.getContentType() != null && entity.getContentType().getElements() != null
&& entity.getContentType().getElements().length > 0) {
ContentType ct = ContentType.get(entity);
charset = ct.getCharset();
}
if (charset == null) {
if (Constants.STATUS_HTTP_204_NO_CONTENT != myResponse.getStatusLine().getStatusCode()) {
ourLog.warn("Response did not specify a charset.");
}
charset = Charset.forName("UTF-8");
}
Reader reader = new InputStreamReader(readEntity(), charset);
return reader;
}
@Override
public InputStream readEntity() throws IOException {
if (this.myEntityBuffered) {
return new ByteArrayInputStream(myEntityBytes);
} else if (myResponse.getEntity() != null) {
return myResponse.getEntity().getContent();
} else {
return null;
}
}
@Override
public void close() {
if (myResponse instanceof CloseableHttpResponse) {
try {
((CloseableHttpResponse) myResponse).close();
} catch (IOException e) {
ourLog.debug("Failed to close response", e);
}
}
}
@Override
public void bufferEntitity() throws IOException {
if (myEntityBuffered) {
return;
}
InputStream respEntity = readEntity();
if (respEntity != null) {
this.myEntityBuffered = true;
try {
this.myEntityBytes = IOUtils.toByteArray(respEntity);
} catch (IllegalStateException e) {
throw new InternalErrorException(e);
}
}
}
}

View File

@ -0,0 +1,139 @@
package ca.uhn.fhir.rest.client.apache;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2016 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.client.ProxyAuthenticationStrategy;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.client.RestfulClientFactory;
import ca.uhn.fhir.rest.client.api.Header;
import ca.uhn.fhir.rest.client.api.IHttpClient;
/**
* A Restful Factory to create clients, requests and responses based on the Apache httpclient library.
*
* @author Peter Van Houte | peter.vanhoute@agfa.com | Agfa Healthcare
*/
public class ApacheRestfulClientFactory extends RestfulClientFactory {
private HttpClient myHttpClient;
private HttpHost myProxy;
/**
* Constructor
*/
public ApacheRestfulClientFactory() {
}
/**
* Constructor
*
* @param theContext
* The context
*/
public ApacheRestfulClientFactory(FhirContext theContext) {
super(theContext);
}
public synchronized HttpClient getNativeHttpClient() {
if (myHttpClient == null) {
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000,
TimeUnit.MILLISECONDS);
connectionManager.setMaxTotal(getPoolMaxTotal());
connectionManager.setDefaultMaxPerRoute(getPoolMaxPerRoute());
// @formatter:off
RequestConfig defaultRequestConfig = RequestConfig.custom().setSocketTimeout(getSocketTimeout())
.setConnectTimeout(getConnectTimeout()).setConnectionRequestTimeout(getConnectionRequestTimeout())
.setStaleConnectionCheckEnabled(true).setProxy(myProxy).build();
HttpClientBuilder builder = HttpClients.custom().setConnectionManager(connectionManager)
.setDefaultRequestConfig(defaultRequestConfig).disableCookieManagement();
if (myProxy != null && StringUtils.isNotBlank(getProxyUsername()) && StringUtils.isNotBlank(getProxyPassword())) {
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(new AuthScope(myProxy.getHostName(), myProxy.getPort()),
new UsernamePasswordCredentials(getProxyUsername(), getProxyPassword()));
builder.setProxyAuthenticationStrategy(new ProxyAuthenticationStrategy());
builder.setDefaultCredentialsProvider(credsProvider);
}
myHttpClient = builder.build();
// @formatter:on
}
return myHttpClient;
}
@Override
public IHttpClient getHttpClient(StringBuilder theUrl, Map<String, List<String>> theIfNoneExistParams,
String theIfNoneExistString, RequestTypeEnum theRequestType, List<Header> theHeaders) {
return new ApacheHttpClient(getNativeHttpClient(), theUrl, theIfNoneExistParams, theIfNoneExistString, theRequestType,
theHeaders);
}
@Override
public void setProxy(String theHost, Integer thePort) {
if (theHost != null) {
myProxy = new HttpHost(theHost, thePort, "http");
} else {
myProxy = null;
}
}
/**
* Only allows to set an instance of type org.apache.http.client.HttpClient
* @see ca.uhn.fhir.rest.client.IRestfulClientFactory#setHttpClient(ca.uhn.fhir.rest.client.api.IHttpClient)
*/
@Override
public synchronized void setHttpClient(Object theHttpClient) {
this.myHttpClient = (HttpClient) theHttpClient;
}
@Override
protected ApacheHttpClient getHttpClient(String theServerBase) {
return new ApacheHttpClient(getNativeHttpClient(), new StringBuilder(theServerBase), null, null, null, null);
}
@Override
protected void resetHttpClient() {
this.myHttpClient = null;
}
}

View File

@ -1,4 +1,4 @@
package ca.uhn.fhir.rest.client.interceptor; package ca.uhn.fhir.rest.client.apache;
/* /*
* #%L * #%L
@ -26,11 +26,12 @@ import java.util.zip.GZIPOutputStream;
import org.apache.http.Header; import org.apache.http.Header;
import org.apache.http.HttpEntityEnclosingRequest; import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.ByteArrayEntity; import org.apache.http.entity.ByteArrayEntity;
import ca.uhn.fhir.rest.client.IClientInterceptor; import ca.uhn.fhir.rest.client.IClientInterceptor;
import ca.uhn.fhir.rest.client.api.IHttpRequest;
import ca.uhn.fhir.rest.client.api.IHttpResponse;
import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.server.Constants;
/** /**
@ -42,7 +43,8 @@ public class GZipContentInterceptor implements IClientInterceptor {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(GZipContentInterceptor.class); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(GZipContentInterceptor.class);
@Override @Override
public void interceptRequest(HttpRequestBase theRequest) { public void interceptRequest(IHttpRequest theRequestInterface) {
HttpRequestBase theRequest = ((ApacheHttpRequest) theRequestInterface).getApacheRequest();
if (theRequest instanceof HttpEntityEnclosingRequest) { if (theRequest instanceof HttpEntityEnclosingRequest) {
Header[] encodingHeaders = theRequest.getHeaders(Constants.HEADER_CONTENT_ENCODING); Header[] encodingHeaders = theRequest.getHeaders(Constants.HEADER_CONTENT_ENCODING);
if (encodingHeaders == null || encodingHeaders.length == 0) { if (encodingHeaders == null || encodingHeaders.length == 0) {
@ -69,7 +71,7 @@ public class GZipContentInterceptor implements IClientInterceptor {
} }
@Override @Override
public void interceptResponse(HttpResponse theResponse) throws IOException { public void interceptResponse(IHttpResponse theResponse) throws IOException {
// nothing // nothing
} }

View File

@ -0,0 +1,54 @@
package ca.uhn.fhir.rest.client.api;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2016 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
/**
* Represents an HTTP header field.
*/
public class Header {
public final String myName;
public final String myValue;
public Header(String myName, String myValue) {
this.myName = myName;
this.myValue = myValue;
}
/**
* Get the name of the Header.
*
* @return the name of the Header, never {@code null}
*/
public String getName() {
return myName;
}
/**
* Get the value of the Header.
*
* @return the value of the Header, may be {@code null}
*/
public String getValue() {
return myValue;
}
}

View File

@ -0,0 +1,66 @@
package ca.uhn.fhir.rest.client.api;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2016 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.util.List;
import java.util.Map;
import org.hl7.fhir.instance.model.api.IBaseBinary;
import ca.uhn.fhir.rest.server.EncodingEnum;
/**
* A HTTP Client interface.
*/
public interface IHttpClient {
/**
* Create a byte request
* @param theContents the contents
* @param theContentType the contentType
* @param theEncoding the encoding
* @return the http request to be executed
*/
IHttpRequest createByteRequest(String theContents, String theContentType, EncodingEnum theEncoding);
/**
* Create a parameter request
* @param theParams the parameters
* @param theEncoding the encoding
* @return the http request to be executed
*/
IHttpRequest createParamRequest(Map<String, List<String>> theParams, EncodingEnum theEncoding);
/**
* Create a binary request
* @param theBinary the binary
* @return the http request to be executed
*/
IHttpRequest createBinaryRequest(IBaseBinary theBinary);
/**
* Create a normal http get request
* @param theEncoding the request encoding
* @return the http request to be executed
*/
IHttpRequest createGetRequest(EncodingEnum theEncoding);
}

View File

@ -0,0 +1,59 @@
package ca.uhn.fhir.rest.client.api;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2016 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.io.IOException;
import java.util.List;
import java.util.Map;
/**
* Http Request. Allows addition of headers and execution of the request.
*/
public interface IHttpRequest {
/**
* Add a header to the request
* @param theName the header name
* @param theValue the header value
*/
public void addHeader(String theName, String theValue);
/**
* Execute the request
* @return the response
* @throws IOException
*/
public IHttpResponse execute() throws IOException;
/**
* @return all request headers in lower case
*/
public Map<String, List<String>> getAllHeaders();
/**
* Return the requestbody as a string.
* If this is not supported by the underlying technology, null is returned
* @return a string representation of the request or null if not supported or empty.
* @throws IOException
*/
public String getRequestBodyFromStream() throws IOException;
}

View File

@ -0,0 +1,102 @@
package ca.uhn.fhir.rest.client.api;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2016 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.util.List;
import java.util.Map;
/**
* An interface around the HTTP Response.
*/
public interface IHttpResponse {
/**
* Get the status code associated with the response.
* @return the response status code.
*/
public int getStatus();
/**
* @return the native response, depending on the client library used
*/
Object getResponse();
/**
* Extracts {@code Content-Type} value from the response exactly as
* specified by the {@code Content-Type} header. Returns {@code null}
* if not specified.
*/
public String getMimeType();
/**
* Get map of the response headers and corresponding string values.
* @return response headers as a map header keys and they values.
*/
public Map<String, List<String>> getAllHeaders();
/**
* Get the response status information reason phrase associated with the response.
* @return the reason phrase.
*/
public String getStatusInfo();
/**
* Returna reader for the response entity
*/
public Reader createReader() throws IOException;
/**
* Read the message entity input stream as an InputStream.
*/
public InputStream readEntity() throws IOException;
/**
* Close the response
*/
public void close();
/**
* Buffer the message entity data.
* <p>
* In case the message entity is backed by an unconsumed entity input stream,
* all the bytes of the original entity input stream are read and stored in a
* local buffer. The original entity input stream is consumed.
* </p>
* <p>
* In case the response entity instance is not backed by an unconsumed input stream
* an invocation of {@code bufferEntity} method is ignored and the method returns.
* </p>
* <p>
* This operation is idempotent, i.e. it can be invoked multiple times with
* the same effect which also means that calling the {@code bufferEntity()}
* method on an already buffered (and thus closed) message instance is legal
* and has no further effect.
* </p>
* <p>
* Buffering the message entity data allows for multiple invocations of
* {@code readEntity(...)} methods on the response instance.
*/
void bufferEntitity() throws IOException;
}

View File

@ -21,7 +21,6 @@ package ca.uhn.fhir.rest.client.api;
*/ */
import org.apache.http.client.HttpClient;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
@ -51,7 +50,7 @@ public interface IRestfulClient {
* Do not call this method in client code. It is a part of the internal HAPI API and * Do not call this method in client code. It is a part of the internal HAPI API and
* is subject to change! * is subject to change!
*/ */
HttpClient getHttpClient(); IHttpClient getHttpClient();
/** /**
* Base URL for the server, with no trailing "/" * Base URL for the server, with no trailing "/"

View File

@ -25,10 +25,10 @@ import java.io.UnsupportedEncodingException;
import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpRequestBase;
import ca.uhn.fhir.rest.client.IClientInterceptor; import ca.uhn.fhir.rest.client.IClientInterceptor;
import ca.uhn.fhir.rest.client.api.IHttpRequest;
import ca.uhn.fhir.rest.client.api.IHttpResponse;
import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
@ -52,7 +52,7 @@ public class BasicAuthInterceptor implements IClientInterceptor {
} }
@Override @Override
public void interceptRequest(HttpRequestBase theRequest) { public void interceptRequest(IHttpRequest theRequest) {
String authorizationUnescaped = StringUtils.defaultString(myUsername) + ":" + StringUtils.defaultString(myPassword); String authorizationUnescaped = StringUtils.defaultString(myUsername) + ":" + StringUtils.defaultString(myPassword);
String encoded; String encoded;
try { try {
@ -64,7 +64,7 @@ public class BasicAuthInterceptor implements IClientInterceptor {
} }
@Override @Override
public void interceptResponse(HttpResponse theResponse) throws IOException { public void interceptResponse(IHttpResponse theResponse) throws IOException {
// nothing // nothing
} }

View File

@ -21,10 +21,10 @@ package ca.uhn.fhir.rest.client.interceptor;
*/ */
import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.Validate;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpRequestBase;
import ca.uhn.fhir.rest.client.IClientInterceptor; import ca.uhn.fhir.rest.client.IClientInterceptor;
import ca.uhn.fhir.rest.client.api.IHttpRequest;
import ca.uhn.fhir.rest.client.api.IHttpResponse;
import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.util.CoverageIgnore; import ca.uhn.fhir.util.CoverageIgnore;
@ -71,12 +71,12 @@ public class BearerTokenAuthInterceptor implements IClientInterceptor {
} }
@Override @Override
public void interceptRequest(HttpRequestBase theRequest) { public void interceptRequest(IHttpRequest theRequest) {
theRequest.addHeader(Constants.HEADER_AUTHORIZATION, (Constants.HEADER_AUTHORIZATION_VALPREFIX_BEARER + myToken)); theRequest.addHeader(Constants.HEADER_AUTHORIZATION, (Constants.HEADER_AUTHORIZATION_VALPREFIX_BEARER + myToken));
} }
@Override @Override
public void interceptResponse(HttpResponse theResponse) { public void interceptResponse(IHttpResponse theResponse) {
// nothing // nothing
} }

View File

@ -20,10 +20,9 @@ package ca.uhn.fhir.rest.client.interceptor;
* #L% * #L%
*/ */
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpRequestBase;
import ca.uhn.fhir.rest.client.IClientInterceptor; import ca.uhn.fhir.rest.client.IClientInterceptor;
import ca.uhn.fhir.rest.client.api.IHttpRequest;
import ca.uhn.fhir.rest.client.api.IHttpResponse;
/** /**
* Client interceptor which simply captures request and response objects and stores them so that they can be inspected after a client * Client interceptor which simply captures request and response objects and stores them so that they can be inspected after a client
@ -31,8 +30,8 @@ import ca.uhn.fhir.rest.client.IClientInterceptor;
*/ */
public class CapturingInterceptor implements IClientInterceptor { public class CapturingInterceptor implements IClientInterceptor {
private HttpRequestBase myLastRequest; private IHttpRequest myLastRequest;
private HttpResponse myLastResponse; private IHttpResponse myLastResponse;
/** /**
* Clear the last request and response values * Clear the last request and response values
@ -42,21 +41,21 @@ public class CapturingInterceptor implements IClientInterceptor {
myLastResponse = null; myLastResponse = null;
} }
public HttpRequestBase getLastRequest() { public IHttpRequest getLastRequest() {
return myLastRequest; return myLastRequest;
} }
public HttpResponse getLastResponse() { public IHttpResponse getLastResponse() {
return myLastResponse; return myLastResponse;
} }
@Override @Override
public void interceptRequest(HttpRequestBase theRequest) { public void interceptRequest(IHttpRequest theRequest) {
myLastRequest = theRequest; myLastRequest = theRequest;
} }
@Override @Override
public void interceptResponse(HttpResponse theRequest) { public void interceptResponse(IHttpResponse theRequest) {
myLastResponse = theRequest; myLastResponse = theRequest;
} }

View File

@ -20,10 +20,9 @@ package ca.uhn.fhir.rest.client.interceptor;
* #L% * #L%
*/ */
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpRequestBase;
import ca.uhn.fhir.rest.client.IClientInterceptor; import ca.uhn.fhir.rest.client.IClientInterceptor;
import ca.uhn.fhir.rest.client.api.IHttpRequest;
import ca.uhn.fhir.rest.client.api.IHttpResponse;
import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.server.Constants;
/** /**
@ -42,12 +41,12 @@ public class CookieInterceptor implements IClientInterceptor {
} }
@Override @Override
public void interceptRequest(HttpRequestBase theRequest) { public void interceptRequest(IHttpRequest theRequest) {
theRequest.addHeader(Constants.HEADER_COOKIE, sessionCookie); //$NON-NLS-1$ theRequest.addHeader(Constants.HEADER_COOKIE, sessionCookie); //$NON-NLS-1$
} }
@Override @Override
public void interceptResponse(HttpResponse theResponse) { public void interceptResponse(IHttpResponse theResponse) {
// nothing // nothing
} }
} }

View File

@ -20,22 +20,19 @@ package ca.uhn.fhir.rest.client.interceptor;
* #L% * #L%
*/ */
import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.Validate;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.HttpEntityWrapper;
import org.slf4j.Logger; import org.slf4j.Logger;
import ca.uhn.fhir.rest.client.IClientInterceptor; import ca.uhn.fhir.rest.client.IClientInterceptor;
import ca.uhn.fhir.rest.client.api.IHttpRequest;
import ca.uhn.fhir.rest.client.api.IHttpResponse;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
public class LoggingInterceptor implements IClientInterceptor { public class LoggingInterceptor implements IClientInterceptor {
@ -74,59 +71,39 @@ public class LoggingInterceptor implements IClientInterceptor {
} }
@Override @Override
public void interceptRequest(HttpRequestBase theRequest) { public void interceptRequest(IHttpRequest theRequest) {
if (myLogRequestSummary) { if (myLogRequestSummary) {
myLog.info("Client request: {}", theRequest); myLog.info("Client request: {}", theRequest);
} }
if (myLogRequestHeaders) { if (myLogRequestHeaders) {
StringBuilder b = new StringBuilder(); StringBuilder b = headersToString(theRequest.getAllHeaders());
for (int i = 0; i < theRequest.getAllHeaders().length; i++) {
Header next = theRequest.getAllHeaders()[i];
b.append(next.getName() + ": " + next.getValue());
if (i + 1 < theRequest.getAllHeaders().length) {
b.append('\n');
}
}
myLog.info("Client request headers:\n{}", b.toString()); myLog.info("Client request headers:\n{}", b.toString());
} }
if (myLogRequestBody) { if (myLogRequestBody) {
if (theRequest instanceof HttpEntityEnclosingRequest) { try {
HttpEntity entity = ((HttpEntityEnclosingRequest) theRequest).getEntity(); String content = theRequest.getRequestBodyFromStream();
if (entity.isRepeatable()) { if (content != null) {
try { myLog.info("Client request body:\n{}", content);
String content = IOUtils.toString(entity.getContent());
myLog.info("Client request body:\n{}", content);
} catch (IllegalStateException e) {
myLog.warn("Failed to replay request contents (during logging attempt, actual FHIR call did not fail)", e);
} catch (IOException e) {
myLog.warn("Failed to replay request contents (during logging attempt, actual FHIR call did not fail)", e);
}
} }
} catch (IllegalStateException e) {
myLog.warn("Failed to replay request contents (during logging attempt, actual FHIR call did not fail)", e);
} catch (IOException e) {
myLog.warn("Failed to replay request contents (during logging attempt, actual FHIR call did not fail)", e);
} }
} }
} }
@Override @Override
public void interceptResponse(HttpResponse theResponse) throws IOException { public void interceptResponse(IHttpResponse theResponse) throws IOException {
if (myLogResponseSummary) { if (myLogResponseSummary) {
String message = "HTTP " + theResponse.getStatusLine().getStatusCode() + " " + theResponse.getStatusLine().getReasonPhrase(); String message = "HTTP " + theResponse.getStatus() + " " + theResponse.getStatusInfo();
myLog.info("Client response: {}", message); myLog.info("Client response: {}", message);
} }
if (myLogResponseHeaders) { if (myLogResponseHeaders) {
StringBuilder b = new StringBuilder(); StringBuilder b = headersToString(theResponse.getAllHeaders());
if (theResponse.getAllHeaders() != null) {
for (int i = 0; i < theResponse.getAllHeaders().length; i++) {
Header next = theResponse.getAllHeaders()[i];
b.append(next.getName() + ": " + next.getValue());
if (i + 1 < theResponse.getAllHeaders().length) {
b.append('\n');
}
}
}
// if (theResponse.getEntity() != null && theResponse.getEntity().getContentEncoding() != null) { // if (theResponse.getEntity() != null && theResponse.getEntity().getContentEncoding() != null) {
// Header next = theResponse.getEntity().getContentEncoding(); // Header next = theResponse.getEntity().getContentEncoding();
// b.append(next.getName() + ": " + next.getValue()); // b.append(next.getName() + ": " + next.getValue());
@ -143,23 +120,46 @@ public class LoggingInterceptor implements IClientInterceptor {
} }
if (myLogResponseBody) { if (myLogResponseBody) {
HttpEntity respEntity = theResponse.getEntity(); theResponse.bufferEntitity();
if (respEntity != null) { InputStream respEntity = null;
final byte[] bytes; try {
try { respEntity = theResponse.readEntity();
bytes = IOUtils.toByteArray(respEntity.getContent()); if (respEntity != null) {
} catch (IllegalStateException e) { final byte[] bytes;
throw new InternalErrorException(e); try {
} bytes = IOUtils.toByteArray(respEntity);
} catch (IllegalStateException e) {
myLog.info("Client response body:\n{}", new String(bytes, "UTF-8")); throw new InternalErrorException(e);
theResponse.setEntity(new MyEntityWrapper(respEntity, bytes)); }
} else { myLog.info("Client response body:\n{}", new String(bytes, "UTF-8"));
myLog.info("Client response body: (none)"); } else {
myLog.info("Client response body: (none)");
}
} finally {
IOUtils.closeQuietly(respEntity);
} }
} }
} }
private StringBuilder headersToString(Map<String, List<String>> theHeaders) {
StringBuilder b = new StringBuilder();
if (theHeaders != null && !theHeaders.isEmpty()) {
Iterator<String> nameEntries = theHeaders.keySet().iterator();
while(nameEntries.hasNext()) {
String key = nameEntries.next();
Iterator<String> values = theHeaders.get(key).iterator();
while(values.hasNext()) {
String value = values.next();
b.append(key + ": " + value);
if (nameEntries.hasNext() || values.hasNext()) {
b.append('\n');
}
}
}
}
return b;
}
/** /**
* Sets a logger to use to log messages (default is a logger with this class' name). This can be used to redirect * Sets a logger to use to log messages (default is a logger with this class' name). This can be used to redirect
* logs to a differently named logger instead. * logs to a differently named logger instead.
@ -214,25 +214,4 @@ public class LoggingInterceptor implements IClientInterceptor {
myLogResponseSummary = theValue; myLogResponseSummary = theValue;
} }
private static class MyEntityWrapper extends HttpEntityWrapper {
private byte[] myBytes;
public MyEntityWrapper(HttpEntity theWrappedEntity, byte[] theBytes) {
super(theWrappedEntity);
myBytes = theBytes;
}
@Override
public InputStream getContent() throws IOException {
return new ByteArrayInputStream(myBytes);
}
@Override
public void writeTo(OutputStream theOutstream) throws IOException {
theOutstream.write(myBytes);
}
}
} }

View File

@ -22,10 +22,9 @@ package ca.uhn.fhir.rest.client.interceptor;
import java.io.IOException; import java.io.IOException;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpRequestBase;
import ca.uhn.fhir.rest.client.IClientInterceptor; import ca.uhn.fhir.rest.client.IClientInterceptor;
import ca.uhn.fhir.rest.client.api.IHttpRequest;
import ca.uhn.fhir.rest.client.api.IHttpResponse;
/** /**
* HTTP interceptor to be used for adding HTTP headers containing user identifying info for auditing purposes to the request * HTTP interceptor to be used for adding HTTP headers containing user identifying info for auditing purposes to the request
@ -48,14 +47,14 @@ public class UserInfoInterceptor implements IClientInterceptor {
} }
@Override @Override
public void interceptRequest(HttpRequestBase theRequest) { public void interceptRequest(IHttpRequest theRequest) {
if(myUserId != null) theRequest.addHeader(HEADER_USER_ID, myUserId); if(myUserId != null) theRequest.addHeader(HEADER_USER_ID, myUserId);
if(myUserName != null) theRequest.addHeader(HEADER_USER_NAME, myUserName); if(myUserName != null) theRequest.addHeader(HEADER_USER_NAME, myUserName);
if(myAppName != null) theRequest.addHeader(HEADER_APPLICATION_NAME, myAppName); if(myAppName != null) theRequest.addHeader(HEADER_APPLICATION_NAME, myAppName);
} }
@Override @Override
public void interceptResponse(HttpResponse theResponse) throws IOException { public void interceptResponse(IHttpResponse theResponse) throws IOException {
// nothing // nothing
} }

View File

@ -28,8 +28,8 @@ import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
class AddTagsMethodBinding extends BaseAddOrDeleteTagsMethodBinding { class AddTagsMethodBinding extends BaseAddOrDeleteTagsMethodBinding {
public AddTagsMethodBinding(Method theMethod, FhirContext theConetxt, Object theProvider, AddTags theAnnotation) { public AddTagsMethodBinding(Method theMethod, FhirContext theContext, Object theProvider, AddTags theAnnotation) {
super(theMethod, theConetxt, theProvider, theAnnotation.type()); super(theMethod, theContext, theProvider, theAnnotation.type());
} }
@Override @Override

View File

@ -56,8 +56,8 @@ abstract class BaseAddOrDeleteTagsMethodBinding extends BaseMethodBinding<Void>
private String myResourceName; private String myResourceName;
private Integer myTagListParamIndex; private Integer myTagListParamIndex;
public BaseAddOrDeleteTagsMethodBinding(Method theMethod, FhirContext theConetxt, Object theProvider, Class<? extends IResource> theTypeFromMethodAnnotation) { public BaseAddOrDeleteTagsMethodBinding(Method theMethod, FhirContext theContext, Object theProvider, Class<? extends IResource> theTypeFromMethodAnnotation) {
super(theMethod, theConetxt, theProvider); super(theMethod, theContext, theProvider);
if (theProvider instanceof IResourceProvider) { if (theProvider instanceof IResourceProvider) {
myType = ((IResourceProvider) theProvider).getResourceType(); myType = ((IResourceProvider) theProvider).getResourceType();
@ -69,7 +69,7 @@ abstract class BaseAddOrDeleteTagsMethodBinding extends BaseMethodBinding<Void>
throw new ConfigurationException("Method '" + theMethod.getName() + "' does not specify a resource type, but has an @" + IdParam.class.getSimpleName() + " parameter. Please specity a resource type in the method annotation on this method"); throw new ConfigurationException("Method '" + theMethod.getName() + "' does not specify a resource type, but has an @" + IdParam.class.getSimpleName() + " parameter. Please specity a resource type in the method annotation on this method");
} }
myResourceName = theConetxt.getResourceDefinition(myType).getName(); myResourceName = theContext.getResourceDefinition(myType).getName();
myIdParamIndex = MethodUtil.findIdParameterIndex(theMethod, getContext()); myIdParamIndex = MethodUtil.findIdParameterIndex(theMethod, getContext());
myVersionIdParamIndex = MethodUtil.findVersionIdParameterIndex(theMethod); myVersionIdParamIndex = MethodUtil.findVersionIdParameterIndex(theMethod);

View File

@ -23,19 +23,10 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
* #L% * #L%
*/ */
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.AbstractHttpEntity;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.message.BasicNameValuePair;
import org.hl7.fhir.instance.model.api.IBaseBinary; import org.hl7.fhir.instance.model.api.IBaseBinary;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
@ -47,10 +38,11 @@ import ca.uhn.fhir.model.valueset.BundleTypeEnum;
import ca.uhn.fhir.parser.DataFormatException; import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.parser.IParser; import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.client.BaseHttpClientInvocation; import ca.uhn.fhir.rest.client.BaseHttpClientInvocation;
import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.client.api.IHttpClient;
import ca.uhn.fhir.rest.client.api.IHttpRequest;
import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.server.EncodingEnum; import ca.uhn.fhir.rest.server.EncodingEnum;
import ca.uhn.fhir.rest.server.IVersionSpecificBundleFactory; import ca.uhn.fhir.rest.server.IVersionSpecificBundleFactory;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
/** /**
* @author James Agnew * @author James Agnew
@ -63,7 +55,6 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
private final BundleTypeEnum myBundleType; private final BundleTypeEnum myBundleType;
private final String myContents; private final String myContents;
private boolean myContentsIsBundle; private boolean myContentsIsBundle;
private final FhirContext myContext;
private Map<String, List<String>> myIfNoneExistParams; private Map<String, List<String>> myIfNoneExistParams;
private String myIfNoneExistString; private String myIfNoneExistString;
private boolean myOmitResourceId = false; private boolean myOmitResourceId = false;
@ -74,7 +65,7 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
private final String myUrlPath; private final String myUrlPath;
public BaseHttpClientInvocationWithContents(FhirContext theContext, Bundle theBundle) { public BaseHttpClientInvocationWithContents(FhirContext theContext, Bundle theBundle) {
myContext = theContext; super(theContext);
myResource = null; myResource = null;
myTagList = null; myTagList = null;
myUrlPath = null; myUrlPath = null;
@ -84,8 +75,9 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
myBundleType = null; myBundleType = null;
} }
public BaseHttpClientInvocationWithContents(FhirContext theContext, IBaseResource theResource, Map<String, List<String>> theParams, String... theUrlPath) { public BaseHttpClientInvocationWithContents(FhirContext theContext, IBaseResource theResource,
myContext = theContext; Map<String, List<String>> theParams, String... theUrlPath) {
super(theContext);
myResource = theResource; myResource = theResource;
myTagList = null; myTagList = null;
myUrlPath = StringUtils.join(theUrlPath, '/'); myUrlPath = StringUtils.join(theUrlPath, '/');
@ -98,8 +90,7 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
} }
public BaseHttpClientInvocationWithContents(FhirContext theContext, IBaseResource theResource, String theUrlPath) { public BaseHttpClientInvocationWithContents(FhirContext theContext, IBaseResource theResource, String theUrlPath) {
super(); super(theContext);
myContext = theContext;
myResource = theResource; myResource = theResource;
myUrlPath = theUrlPath; myUrlPath = theUrlPath;
myTagList = null; myTagList = null;
@ -109,8 +100,9 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
myBundleType = null; myBundleType = null;
} }
public BaseHttpClientInvocationWithContents(FhirContext theContext, List<? extends IBaseResource> theResources, BundleTypeEnum theBundleType) { public BaseHttpClientInvocationWithContents(FhirContext theContext, List<? extends IBaseResource> theResources,
myContext = theContext; BundleTypeEnum theBundleType) {
super(theContext);
myResource = null; myResource = null;
myTagList = null; myTagList = null;
myUrlPath = null; myUrlPath = null;
@ -120,8 +112,9 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
myBundleType = theBundleType; myBundleType = theBundleType;
} }
public BaseHttpClientInvocationWithContents(FhirContext theContext, Map<String, List<String>> theParams, String... theUrlPath) { public BaseHttpClientInvocationWithContents(FhirContext theContext, Map<String, List<String>> theParams,
myContext = theContext; String... theUrlPath) {
super(theContext);
myResource = null; myResource = null;
myTagList = null; myTagList = null;
myUrlPath = StringUtils.join(theUrlPath, '/'); myUrlPath = StringUtils.join(theUrlPath, '/');
@ -133,8 +126,9 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
myBundleType = null; myBundleType = null;
} }
public BaseHttpClientInvocationWithContents(FhirContext theContext, String theContents, boolean theIsBundle, String theUrlPath) { public BaseHttpClientInvocationWithContents(FhirContext theContext, String theContents, boolean theIsBundle,
myContext = theContext; String theUrlPath) {
super(theContext);
myResource = null; myResource = null;
myTagList = null; myTagList = null;
myUrlPath = theUrlPath; myUrlPath = theUrlPath;
@ -145,8 +139,9 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
myBundleType = null; myBundleType = null;
} }
public BaseHttpClientInvocationWithContents(FhirContext theContext, String theContents, Map<String, List<String>> theParams, String... theUrlPath) { public BaseHttpClientInvocationWithContents(FhirContext theContext, String theContents,
myContext = theContext; Map<String, List<String>> theParams, String... theUrlPath) {
super(theContext);
myResource = null; myResource = null;
myTagList = null; myTagList = null;
myUrlPath = StringUtils.join(theUrlPath, '/'); myUrlPath = StringUtils.join(theUrlPath, '/');
@ -159,13 +154,12 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
} }
public BaseHttpClientInvocationWithContents(FhirContext theContext, TagList theTagList, String... theUrlPath) { public BaseHttpClientInvocationWithContents(FhirContext theContext, TagList theTagList, String... theUrlPath) {
super(); super(theContext);
if (theTagList == null) { if (theTagList == null) {
throw new NullPointerException("Tag list must not be null"); throw new NullPointerException("Tag list must not be null");
} }
myResource = null; myResource = null;
myContext = theContext;
myTagList = theTagList; myTagList = theTagList;
myResources = null; myResources = null;
myBundle = null; myBundle = null;
@ -175,23 +169,8 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
myUrlPath = StringUtils.join(theUrlPath, '/'); myUrlPath = StringUtils.join(theUrlPath, '/');
} }
private void addMatchHeaders(HttpRequestBase theHttpRequest, StringBuilder theUrlBase) {
if (myIfNoneExistParams != null) {
StringBuilder b = newHeaderBuilder(theUrlBase);
appendExtraParamsWithQuestionMark(myIfNoneExistParams, b, b.indexOf("?") == -1);
theHttpRequest.addHeader(Constants.HEADER_IF_NONE_EXIST, b.toString());
}
if (myIfNoneExistString != null) {
StringBuilder b = newHeaderBuilder(theUrlBase);
b.append(b.indexOf("?") == -1 ? '?' : '&');
b.append(myIfNoneExistString.substring(myIfNoneExistString.indexOf('?') + 1));
theHttpRequest.addHeader(Constants.HEADER_IF_NONE_EXIST, b.toString());
}
}
@Override @Override
public HttpRequestBase asHttpRequest(String theUrlBase, Map<String, List<String>> theExtraParams, EncodingEnum theEncoding, Boolean thePrettyPrint) throws DataFormatException { public IHttpRequest asHttpRequest(String theUrlBase, Map<String, List<String>> theExtraParams, EncodingEnum theEncoding, Boolean thePrettyPrint) throws DataFormatException {
StringBuilder url = new StringBuilder(); StringBuilder url = new StringBuilder();
if (myUrlPath == null) { if (myUrlPath == null) {
@ -207,43 +186,46 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
} }
appendExtraParamsWithQuestionMark(theExtraParams, url, url.indexOf("?") == -1); appendExtraParamsWithQuestionMark(theExtraParams, url, url.indexOf("?") == -1);
IHttpClient httpClient = getRestfulClientFactory().getHttpClient(url, myIfNoneExistParams, myIfNoneExistString, getRequestType(), getHeaders());
if (myResource != null && IBaseBinary.class.isAssignableFrom(myResource.getClass())) { if (myResource != null && IBaseBinary.class.isAssignableFrom(myResource.getClass())) {
IBaseBinary binary = (IBaseBinary) myResource; return httpClient.createBinaryRequest((IBaseBinary) myResource);
if (isBlank(binary.getContentType()) || EncodingEnum.forContentTypeStrict(binary.getContentType()) != null) { } else {
ourLog.trace("Binary has Content-Type {}, encoding as a FHIR resource instead of raw", binary.getContentType()); EncodingEnum encoding = theEncoding;
} else { if (myContents != null) {
/* encoding = MethodUtil.detectEncoding(myContents);
* Note: Be careful about changing which constructor we use for ByteArrayEntity, }
* as Android's version of HTTPClient doesn't support the newer ones for
* whatever reason.
*/
ByteArrayEntity entity = new ByteArrayEntity(binary.getContent());
HttpRequestBase retVal = createRequest(url, entity); if (encoding == null) {
addMatchHeaders(retVal, url); encoding = EncodingEnum.XML;
super.addHeadersToRequest(retVal, null); }
if (isNotBlank(binary.getContentType())) {
retVal.addHeader(Constants.HEADER_CONTENT_TYPE, binary.getContentType()); if (myParams != null) {
} return httpClient.createParamRequest(myParams, encoding);
return retVal; } else {
String contents = parseContents(thePrettyPrint, encoding);
String contentType = getContentType(encoding);
return httpClient.createByteRequest(contents, contentType, encoding);
} }
} }
}
IParser parser; private String getContentType(EncodingEnum encoding) {
String contentType; if (myBundle != null || (getFhirContext().getVersion().getVersion() == FhirVersionEnum.DSTU1
EncodingEnum encoding = null; && ((myContents != null && myContentsIsBundle) || myResources != null))) {
encoding = theEncoding; return encoding.getBundleContentType();
} else {
if (myContents != null) { return encoding.getResourceContentType();
encoding = MethodUtil.detectEncoding(myContents);
} }
}
private String parseContents(Boolean thePrettyPrint, EncodingEnum encoding) {
IParser parser;
if (encoding == EncodingEnum.JSON) { if (encoding == EncodingEnum.JSON) {
parser = myContext.newJsonParser(); parser = getFhirContext().newJsonParser();
} else { } else {
encoding = EncodingEnum.XML; parser = getFhirContext().newXmlParser();
parser = myContext.newXmlParser();
} }
if (thePrettyPrint != null) { if (thePrettyPrint != null) {
@ -251,84 +233,27 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
} }
parser.setOmitResourceId(myOmitResourceId); parser.setOmitResourceId(myOmitResourceId);
if (myTagList != null) {
AbstractHttpEntity entity; return parser.encodeTagListToString(myTagList);
if (myParams != null) { } else if (myBundle != null) {
contentType = null; return parser.encodeBundleToString(myBundle);
List<NameValuePair> parameters = new ArrayList<NameValuePair>(); } else if (myResources != null) {
for (Entry<String, List<String>> nextParam : myParams.entrySet()) { IVersionSpecificBundleFactory bundleFactory = getFhirContext().newBundleFactory();
List<String> value = nextParam.getValue(); bundleFactory.initializeBundleFromResourceList("", myResources, "", "", myResources.size(), myBundleType);
for (String s : value) { Bundle bundle = bundleFactory.getDstu1Bundle();
parameters.add(new BasicNameValuePair(nextParam.getKey(), s)); if (bundle != null) {
} return parser.encodeBundleToString(bundle);
}
try {
entity = new UrlEncodedFormEntity(parameters, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new InternalErrorException("Server does not support UTF-8 (should not happen)", e);
}
} else {
String contents;
if (myTagList != null) {
contents = parser.encodeTagListToString(myTagList);
contentType = encoding.getResourceContentType();
} else if (myBundle != null) {
contents = parser.encodeBundleToString(myBundle);
contentType = encoding.getBundleContentType();
} else if (myResources != null) {
IVersionSpecificBundleFactory bundleFactory = myContext.newBundleFactory();
bundleFactory.initializeBundleFromResourceList("", myResources, "", "", myResources.size(), myBundleType);
Bundle bundle = bundleFactory.getDstu1Bundle();
if (bundle != null) {
contents = parser.encodeBundleToString(bundle);
contentType = encoding.getBundleContentType();
} else {
IBaseResource bundleRes = bundleFactory.getResourceBundle();
contents = parser.encodeResourceToString(bundleRes);
contentType = encoding.getResourceContentType();
}
} else if (myContents != null) {
contents = myContents;
if (myContentsIsBundle && myContext.getVersion().getVersion().equals(FhirVersionEnum.DSTU1)) {
contentType = encoding.getBundleContentType();
} else {
contentType = encoding.getResourceContentType();
}
} else { } else {
contents = parser.encodeResourceToString(myResource); IBaseResource bundleRes = bundleFactory.getResourceBundle();
contentType = encoding.getResourceContentType(); return parser.encodeResourceToString(bundleRes);
} }
} else if (myContents != null) {
/* return myContents;
* We aren't using a StringEntity here because the constructors supported by } else {
* Android aren't available in non-Android, and vice versa. Since we add the return parser.encodeResourceToString(myResource);
* content type header manually, it makes no difference which one
* we use anyhow.
*/
entity = new ByteArrayEntity(contents.getBytes(Constants.CHARSET_UTF8));
} }
HttpRequestBase retVal = createRequest(url, entity);
super.addHeadersToRequest(retVal, encoding);
addMatchHeaders(retVal, url);
if (contentType != null) {
retVal.addHeader(Constants.HEADER_CONTENT_TYPE, contentType + Constants.HEADER_SUFFIX_CT_UTF_8);
}
return retVal;
} }
protected abstract HttpRequestBase createRequest(StringBuilder theUrl, AbstractHttpEntity theEntity);
private StringBuilder newHeaderBuilder(StringBuilder theUrlBase) {
StringBuilder b = new StringBuilder();
b.append(theUrlBase);
if (theUrlBase.length() > 0 && theUrlBase.charAt(theUrlBase.length() - 1) == '/') {
b.deleteCharAt(b.length() - 1);
}
return b;
}
public void setIfNoneExistParams(Map<String, List<String>> theIfNoneExist) { public void setIfNoneExistParams(Map<String, List<String>> theIfNoneExist) {
myIfNoneExistParams = theIfNoneExist; myIfNoneExistParams = theIfNoneExist;
} }
@ -341,4 +266,9 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
myOmitResourceId = theOmitResourceId; myOmitResourceId = theOmitResourceId;
} }
/**
* Get the HTTP request type.
*/
protected abstract RequestTypeEnum getRequestType();
} }

View File

@ -60,7 +60,7 @@ public class ConformanceMethodBinding extends BaseResourceReturningMethodBinding
@Override @Override
public HttpGetClientInvocation invokeClient(Object[] theArgs) throws InternalErrorException { public HttpGetClientInvocation invokeClient(Object[] theArgs) throws InternalErrorException {
HttpGetClientInvocation retVal = MethodUtil.createConformanceInvocation(); HttpGetClientInvocation retVal = MethodUtil.createConformanceInvocation(getContext());
if (theArgs != null) { if (theArgs != null) {
for (int idx = 0; idx < theArgs.length; idx++) { for (int idx = 0; idx < theArgs.length; idx++) {

View File

@ -119,7 +119,7 @@ public class DeleteMethodBinding extends BaseOutcomeReturningMethodBinding {
throw new InvalidRequestException("ID parameter has the wrong resource type, expected '" + getResourceName() + "', found: " + idDt.getResourceType()); throw new InvalidRequestException("ID parameter has the wrong resource type, expected '" + getResourceName() + "', found: " + idDt.getResourceType());
} }
HttpDeleteClientInvocation retVal = createDeleteInvocation(idDt); HttpDeleteClientInvocation retVal = createDeleteInvocation(getContext(), idDt);
for (int idx = 0; idx < theArgs.length; idx++) { for (int idx = 0; idx < theArgs.length; idx++) {
IParameter nextParam = getParameters().get(idx); IParameter nextParam = getParameters().get(idx);
@ -129,8 +129,8 @@ public class DeleteMethodBinding extends BaseOutcomeReturningMethodBinding {
return retVal; return retVal;
} }
public static HttpDeleteClientInvocation createDeleteInvocation(IIdType theId) { public static HttpDeleteClientInvocation createDeleteInvocation(FhirContext theContext, IIdType theId) {
HttpDeleteClientInvocation retVal = new HttpDeleteClientInvocation(theId); HttpDeleteClientInvocation retVal = new HttpDeleteClientInvocation(theContext, theId);
return retVal; return retVal;
} }
@ -144,13 +144,13 @@ public class DeleteMethodBinding extends BaseOutcomeReturningMethodBinding {
return null; return null;
} }
public static HttpDeleteClientInvocation createDeleteInvocation(String theSearchUrl) { public static HttpDeleteClientInvocation createDeleteInvocation(FhirContext theContext, String theSearchUrl) {
HttpDeleteClientInvocation retVal = new HttpDeleteClientInvocation(theSearchUrl); HttpDeleteClientInvocation retVal = new HttpDeleteClientInvocation(theContext, theSearchUrl);
return retVal; return retVal;
} }
public static HttpDeleteClientInvocation createDeleteInvocation(String theResourceType, Map<String, List<String>> theParams) { public static HttpDeleteClientInvocation createDeleteInvocation(FhirContext theContext, String theResourceType, Map<String, List<String>> theParams) {
return new HttpDeleteClientInvocation(theResourceType, theParams); return new HttpDeleteClientInvocation(theContext, theResourceType, theParams);
} }
} }

View File

@ -28,8 +28,8 @@ import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
public class DeleteTagsMethodBinding extends BaseAddOrDeleteTagsMethodBinding { public class DeleteTagsMethodBinding extends BaseAddOrDeleteTagsMethodBinding {
public DeleteTagsMethodBinding(Method theMethod, FhirContext theConetxt, Object theProvider, DeleteTags theDeleteTags) { public DeleteTagsMethodBinding(Method theMethod, FhirContext theContext, Object theProvider, DeleteTags theDeleteTags) {
super(theMethod, theConetxt, theProvider, theDeleteTags.type()); super(theMethod, theContext, theProvider, theDeleteTags.type());
} }
@Override @Override

View File

@ -48,8 +48,8 @@ public class DynamicSearchMethodBinding extends BaseResourceReturningMethodBindi
private HashSet<String> myParamNames; private HashSet<String> myParamNames;
private Integer myIdParamIndex; private Integer myIdParamIndex;
public DynamicSearchMethodBinding(Class<? extends IBaseResource> theReturnResourceType, Method theMethod, FhirContext theConetxt, IDynamicSearchResourceProvider theProvider) { public DynamicSearchMethodBinding(Class<? extends IBaseResource> theReturnResourceType, Method theMethod, FhirContext theContext, IDynamicSearchResourceProvider theProvider) {
super(theReturnResourceType, theMethod, theConetxt, theProvider); super(theReturnResourceType, theMethod, theContext, theProvider);
myProvider = theProvider; myProvider = theProvider;
mySearchParameters = myProvider.getSearchParameters(); mySearchParameters = myProvider.getSearchParameters();

View File

@ -54,8 +54,8 @@ public class GetTagsMethodBinding extends BaseMethodBinding<TagList> {
private Class<? extends IBaseResource> myType; private Class<? extends IBaseResource> myType;
private Integer myVersionIdParamIndex; private Integer myVersionIdParamIndex;
public GetTagsMethodBinding(Method theMethod, FhirContext theConetxt, Object theProvider, GetTags theAnnotation) { public GetTagsMethodBinding(Method theMethod, FhirContext theContext, Object theProvider, GetTags theAnnotation) {
super(theMethod, theConetxt, theProvider); super(theMethod, theContext, theProvider);
if (theProvider instanceof IResourceProvider) { if (theProvider instanceof IResourceProvider) {
myType = ((IResourceProvider) theProvider).getResourceType(); myType = ((IResourceProvider) theProvider).getResourceType();
@ -64,7 +64,7 @@ public class GetTagsMethodBinding extends BaseMethodBinding<TagList> {
} }
if (!Modifier.isInterface(myType.getModifiers())) { if (!Modifier.isInterface(myType.getModifiers())) {
myResourceName = theConetxt.getResourceDefinition(myType).getName(); myResourceName = theContext.getResourceDefinition(myType).getName();
} }
myIdParamIndex = MethodUtil.findIdParameterIndex(theMethod, getContext()); myIdParamIndex = MethodUtil.findIdParameterIndex(theMethod, getContext());
@ -127,17 +127,17 @@ public class GetTagsMethodBinding extends BaseMethodBinding<TagList> {
if (myType != IResource.class) { if (myType != IResource.class) {
if (id != null) { if (id != null) {
if (versionId != null) { if (versionId != null) {
retVal = new HttpGetClientInvocation(getResourceName(), id.getIdPart(), Constants.PARAM_HISTORY, versionId.getValue(), Constants.PARAM_TAGS); retVal = new HttpGetClientInvocation(getContext(), getResourceName(), id.getIdPart(), Constants.PARAM_HISTORY, versionId.getValue(), Constants.PARAM_TAGS);
} else if (id.hasVersionIdPart()) { } else if (id.hasVersionIdPart()) {
retVal = new HttpGetClientInvocation(getResourceName(), id.getIdPart(), Constants.PARAM_HISTORY, id.getVersionIdPart(), Constants.PARAM_TAGS); retVal = new HttpGetClientInvocation(getContext(), getResourceName(), id.getIdPart(), Constants.PARAM_HISTORY, id.getVersionIdPart(), Constants.PARAM_TAGS);
} else { } else {
retVal = new HttpGetClientInvocation(getResourceName(), id.getIdPart(), Constants.PARAM_TAGS); retVal = new HttpGetClientInvocation(getContext(), getResourceName(), id.getIdPart(), Constants.PARAM_TAGS);
} }
} else { } else {
retVal = new HttpGetClientInvocation(getResourceName(), Constants.PARAM_TAGS); retVal = new HttpGetClientInvocation(getContext(), getResourceName(), Constants.PARAM_TAGS);
} }
} else { } else {
retVal = new HttpGetClientInvocation(Constants.PARAM_TAGS); retVal = new HttpGetClientInvocation(getContext(), Constants.PARAM_TAGS);
} }
if (theArgs != null) { if (theArgs != null) {

View File

@ -53,8 +53,8 @@ public class HistoryMethodBinding extends BaseResourceReturningMethodBinding {
private String myResourceName; private String myResourceName;
private final RestOperationTypeEnum myResourceOperationType; private final RestOperationTypeEnum myResourceOperationType;
public HistoryMethodBinding(Method theMethod, FhirContext theConetxt, Object theProvider) { public HistoryMethodBinding(Method theMethod, FhirContext theContext, Object theProvider) {
super(toReturnType(theMethod, theProvider), theMethod, theConetxt, theProvider); super(toReturnType(theMethod, theProvider), theMethod, theContext, theProvider);
myIdParamIndex = MethodUtil.findIdParameterIndex(theMethod, getContext()); myIdParamIndex = MethodUtil.findIdParameterIndex(theMethod, getContext());
@ -80,7 +80,7 @@ public class HistoryMethodBinding extends BaseResourceReturningMethodBinding {
} }
if (type != IResource.class) { if (type != IResource.class) {
myResourceName = theConetxt.getResourceDefinition(type).getName(); myResourceName = theContext.getResourceDefinition(type).getName();
} else { } else {
myResourceName = null; myResourceName = null;
} }
@ -142,7 +142,7 @@ public class HistoryMethodBinding extends BaseResourceReturningMethodBinding {
} }
String historyId = id != null ? id.getIdPart() : null; String historyId = id != null ? id.getIdPart() : null;
HttpGetClientInvocation retVal = createHistoryInvocation(resourceName, historyId, null, null); HttpGetClientInvocation retVal = createHistoryInvocation(getContext(), resourceName, historyId, null, null);
if (theArgs != null) { if (theArgs != null) {
for (int idx = 0; idx < theArgs.length; idx++) { for (int idx = 0; idx < theArgs.length; idx++) {
@ -206,7 +206,7 @@ public class HistoryMethodBinding extends BaseResourceReturningMethodBinding {
}; };
} }
public static HttpGetClientInvocation createHistoryInvocation(String theResourceName, String theId, IPrimitiveType<Date> theSince, Integer theLimit) { public static HttpGetClientInvocation createHistoryInvocation(FhirContext theContext, String theResourceName, String theId, IPrimitiveType<Date> theSince, Integer theLimit) {
StringBuilder b = new StringBuilder(); StringBuilder b = new StringBuilder();
if (theResourceName != null) { if (theResourceName != null) {
b.append(theResourceName); b.append(theResourceName);
@ -230,7 +230,7 @@ public class HistoryMethodBinding extends BaseResourceReturningMethodBinding {
b.append(Constants.PARAM_COUNT).append('=').append(theLimit); b.append(Constants.PARAM_COUNT).append('=').append(theLimit);
} }
HttpGetClientInvocation retVal = new HttpGetClientInvocation(b.toString()); HttpGetClientInvocation retVal = new HttpGetClientInvocation(theContext, b.toString());
return retVal; return retVal;
} }

View File

@ -23,11 +23,12 @@ package ca.uhn.fhir.rest.method;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpRequestBase;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.client.BaseHttpClientInvocation; import ca.uhn.fhir.rest.client.BaseHttpClientInvocation;
import ca.uhn.fhir.rest.client.api.IHttpRequest;
import ca.uhn.fhir.rest.server.EncodingEnum; import ca.uhn.fhir.rest.server.EncodingEnum;
public class HttpDeleteClientInvocation extends BaseHttpClientInvocation { public class HttpDeleteClientInvocation extends BaseHttpClientInvocation {
@ -35,22 +36,24 @@ public class HttpDeleteClientInvocation extends BaseHttpClientInvocation {
private String myUrlPath; private String myUrlPath;
private Map<String, List<String>> myParams; private Map<String, List<String>> myParams;
public HttpDeleteClientInvocation(IIdType theId) { public HttpDeleteClientInvocation(FhirContext theContext, IIdType theId) {
super(); super(theContext);
myUrlPath = theId.toUnqualifiedVersionless().getValue(); myUrlPath = theId.toUnqualifiedVersionless().getValue();
} }
public HttpDeleteClientInvocation(String theSearchUrl) { public HttpDeleteClientInvocation(FhirContext theContext, String theSearchUrl) {
super(theContext);
myUrlPath = theSearchUrl; myUrlPath = theSearchUrl;
} }
public HttpDeleteClientInvocation(String theResourceType, Map<String, List<String>> theParams) { public HttpDeleteClientInvocation(FhirContext theContext, String theResourceType, Map<String, List<String>> theParams) {
super(theContext);
myUrlPath = theResourceType; myUrlPath = theResourceType;
myParams = theParams; myParams = theParams;
} }
@Override @Override
public HttpRequestBase asHttpRequest(String theUrlBase, Map<String, List<String>> theExtraParams, EncodingEnum theEncoding, Boolean thePrettyPrint) { public IHttpRequest asHttpRequest(String theUrlBase, Map<String, List<String>> theExtraParams, EncodingEnum theEncoding, Boolean thePrettyPrint) {
StringBuilder b = new StringBuilder(); StringBuilder b = new StringBuilder();
b.append(theUrlBase); b.append(theUrlBase);
if (!theUrlBase.endsWith("/")) { if (!theUrlBase.endsWith("/")) {
@ -61,9 +64,7 @@ public class HttpDeleteClientInvocation extends BaseHttpClientInvocation {
appendExtraParamsWithQuestionMark(myParams, b, b.indexOf("?") == -1); appendExtraParamsWithQuestionMark(myParams, b, b.indexOf("?") == -1);
appendExtraParamsWithQuestionMark(theExtraParams, b, b.indexOf("?") == -1); appendExtraParamsWithQuestionMark(theExtraParams, b, b.indexOf("?") == -1);
HttpDelete retVal = new HttpDelete(b.toString()); return createHttpRequest(b.toString(), theEncoding, RequestTypeEnum.DELETE);
super.addHeadersToRequest(retVal, theEncoding);
return retVal;
} }
} }

View File

@ -28,10 +28,12 @@ import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.methods.HttpGet;
import ca.uhn.fhir.context.ConfigurationException; import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.client.BaseHttpClientInvocation; import ca.uhn.fhir.rest.client.BaseHttpClientInvocation;
import ca.uhn.fhir.rest.client.api.IHttpRequest;
import ca.uhn.fhir.rest.server.EncodingEnum; import ca.uhn.fhir.rest.server.EncodingEnum;
/** /**
@ -43,28 +45,33 @@ public class HttpGetClientInvocation extends BaseHttpClientInvocation {
private final Map<String, List<String>> myParameters; private final Map<String, List<String>> myParameters;
private final String myUrlPath; private final String myUrlPath;
public HttpGetClientInvocation(Map<String, List<String>> theParameters, String... theUrlFragments) { public HttpGetClientInvocation(FhirContext theContext, Map<String, List<String>> theParameters, String... theUrlFragments) {
super(theContext);
myParameters = theParameters; myParameters = theParameters;
myUrlPath = StringUtils.join(theUrlFragments, '/'); myUrlPath = StringUtils.join(theUrlFragments, '/');
} }
public HttpGetClientInvocation(Map<String, List<String>> theParameters, List<String> theUrlFragments) { public HttpGetClientInvocation(FhirContext theContext, Map<String, List<String>> theParameters, List<String> theUrlFragments) {
super(theContext);
myParameters = theParameters; myParameters = theParameters;
myUrlPath = StringUtils.join(theUrlFragments, '/'); myUrlPath = StringUtils.join(theUrlFragments, '/');
} }
public HttpGetClientInvocation(String theUrlPath) { public HttpGetClientInvocation(FhirContext theContext, String theUrlPath) {
super(theContext);
myParameters = new HashMap<String, List<String>>(); myParameters = new HashMap<String, List<String>>();
myUrlPath = theUrlPath; myUrlPath = theUrlPath;
} }
public HttpGetClientInvocation(String... theUrlFragments) { public HttpGetClientInvocation(FhirContext theContext, String... theUrlFragments) {
super(theContext);
myParameters = new HashMap<String, List<String>>(); myParameters = new HashMap<String, List<String>>();
myUrlPath = StringUtils.join(theUrlFragments, '/'); myUrlPath = StringUtils.join(theUrlFragments, '/');
} }
public HttpGetClientInvocation(List<String> theUrlFragments) { public HttpGetClientInvocation(FhirContext theContext, List<String> theUrlFragments) {
super(theContext);
myParameters = new HashMap<String, List<String>>(); myParameters = new HashMap<String, List<String>>();
myUrlPath = StringUtils.join(theUrlFragments, '/'); myUrlPath = StringUtils.join(theUrlFragments, '/');
} }
@ -78,7 +85,7 @@ public class HttpGetClientInvocation extends BaseHttpClientInvocation {
} }
@Override @Override
public HttpGet asHttpRequest(String theUrlBase, Map<String, List<String>> theExtraParams, EncodingEnum theEncoding, Boolean thePrettyPrint) { public IHttpRequest asHttpRequest(String theUrlBase, Map<String, List<String>> theExtraParams, EncodingEnum theEncoding, Boolean thePrettyPrint) {
StringBuilder b = new StringBuilder(); StringBuilder b = new StringBuilder();
if (!myUrlPath.contains("://")) { if (!myUrlPath.contains("://")) {
@ -102,10 +109,7 @@ public class HttpGetClientInvocation extends BaseHttpClientInvocation {
appendExtraParamsWithQuestionMark(theExtraParams, b, first); appendExtraParamsWithQuestionMark(theExtraParams, b, first);
HttpGet retVal = new HttpGet(b.toString()); return super.createHttpRequest(b.toString(), theEncoding, RequestTypeEnum.GET);
super.addHeadersToRequest(retVal, theEncoding);
return retVal;
} }
private boolean addQueryParameter(StringBuilder b, boolean first, String nextKey, String nextValue) { private boolean addQueryParameter(StringBuilder b, boolean first, String nextKey, String nextValue) {

View File

@ -23,14 +23,13 @@ package ca.uhn.fhir.rest.method;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.AbstractHttpEntity;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.Bundle; import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.TagList; import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.model.valueset.BundleTypeEnum; import ca.uhn.fhir.model.valueset.BundleTypeEnum;
import ca.uhn.fhir.rest.api.RequestTypeEnum;
public class HttpPostClientInvocation extends BaseHttpClientInvocationWithContents { public class HttpPostClientInvocation extends BaseHttpClientInvocationWithContents {
@ -63,11 +62,8 @@ public class HttpPostClientInvocation extends BaseHttpClientInvocationWithConten
super(theContext, theParams, theUrlExtension); super(theContext, theParams, theUrlExtension);
} }
@Override protected RequestTypeEnum getRequestType() {
protected HttpPost createRequest(StringBuilder theUrlBase, AbstractHttpEntity theEntity) { return RequestTypeEnum.POST;
HttpPost retVal = new HttpPost(theUrlBase.toString());
retVal.setEntity(theEntity);
return retVal;
} }
} }

View File

@ -20,12 +20,10 @@ package ca.uhn.fhir.rest.method;
* #L% * #L%
*/ */
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.AbstractHttpEntity;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.api.RequestTypeEnum;
public class HttpPutClientInvocation extends BaseHttpClientInvocationWithContents { public class HttpPutClientInvocation extends BaseHttpClientInvocationWithContents {
@ -38,10 +36,8 @@ public class HttpPutClientInvocation extends BaseHttpClientInvocationWithContent
} }
@Override @Override
protected HttpRequestBase createRequest(StringBuilder theUrl, AbstractHttpEntity theEntity) { protected RequestTypeEnum getRequestType() {
HttpPut retVal = new HttpPut(theUrl.toString()); return RequestTypeEnum.PUT;
retVal.setEntity(theEntity);
return retVal;
} }
} }

View File

@ -23,25 +23,24 @@ package ca.uhn.fhir.rest.method;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.apache.http.client.methods.HttpGet; import ca.uhn.fhir.context.FhirContext;
import org.apache.http.client.methods.HttpRequestBase; import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.client.BaseHttpClientInvocation; import ca.uhn.fhir.rest.client.BaseHttpClientInvocation;
import ca.uhn.fhir.rest.client.api.IHttpRequest;
import ca.uhn.fhir.rest.server.EncodingEnum; import ca.uhn.fhir.rest.server.EncodingEnum;
public class HttpSimpleGetClientInvocation extends BaseHttpClientInvocation { public class HttpSimpleGetClientInvocation extends BaseHttpClientInvocation {
private final String myUrl; private final String myUrl;
public HttpSimpleGetClientInvocation(String theUrlPath) { public HttpSimpleGetClientInvocation(FhirContext theContext, String theUrlPath) {
super(theContext);
myUrl = theUrlPath; myUrl = theUrlPath;
} }
@Override @Override
public HttpRequestBase asHttpRequest(String theUrlBase, Map<String, List<String>> theExtraParams, EncodingEnum theEncoding, Boolean thePrettyPrint) { public IHttpRequest asHttpRequest(String theUrlBase, Map<String, List<String>> theExtraParams, EncodingEnum theEncoding, Boolean thePrettyPrint) {
HttpGet retVal = new HttpGet(myUrl); return createHttpRequest(myUrl, theEncoding, RequestTypeEnum.GET);
super.addHeadersToRequest(retVal, theEncoding);
return retVal;
} }
} }

View File

@ -24,7 +24,6 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.utils.DateUtils;
import org.hl7.fhir.instance.model.api.IAnyResource; import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBaseMetaType; import org.hl7.fhir.instance.model.api.IBaseMetaType;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
@ -89,6 +88,7 @@ import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.EncodingEnum; import ca.uhn.fhir.rest.server.EncodingEnum;
import ca.uhn.fhir.rest.server.IDynamicSearchResourceProvider; import ca.uhn.fhir.rest.server.IDynamicSearchResourceProvider;
import ca.uhn.fhir.rest.server.SearchParameterMap; import ca.uhn.fhir.rest.server.SearchParameterMap;
import ca.uhn.fhir.util.DateUtils;
import ca.uhn.fhir.util.ReflectionUtil; import ca.uhn.fhir.util.ReflectionUtil;
/* /*
@ -146,8 +146,8 @@ public class MethodUtil {
return value; return value;
} }
public static HttpGetClientInvocation createConformanceInvocation() { public static HttpGetClientInvocation createConformanceInvocation(FhirContext theContext) {
return new HttpGetClientInvocation("metadata"); return new HttpGetClientInvocation(theContext, "metadata");
} }
public static HttpPostClientInvocation createCreateInvocation(IBaseResource theResource, FhirContext theContext) { public static HttpPostClientInvocation createCreateInvocation(IBaseResource theResource, FhirContext theContext) {

View File

@ -358,7 +358,7 @@ public class OperationMethodBinding extends BaseResourceReturningMethodBinding {
IPrimitiveType<?> primitive = (IPrimitiveType<?>) value; IPrimitiveType<?> primitive = (IPrimitiveType<?>) value;
params.get(nextName).add(primitive.getValueAsString()); params.get(nextName).add(primitive.getValueAsString());
} }
return new HttpGetClientInvocation(params, b.toString()); return new HttpGetClientInvocation(theContext, params, b.toString());
} }
} }

View File

@ -167,15 +167,15 @@ public class ReadMethodBinding extends BaseResourceReturningMethodBinding implem
if (myVersionIdIndex == null) { if (myVersionIdIndex == null) {
String resourceName = getResourceName(); String resourceName = getResourceName();
if (id.hasVersionIdPart()) { if (id.hasVersionIdPart()) {
retVal = createVReadInvocation(new IdDt(resourceName, id.getIdPart(), id.getVersionIdPart()), resourceName); retVal = createVReadInvocation(getContext(), new IdDt(resourceName, id.getIdPart(), id.getVersionIdPart()), resourceName);
} else { } else {
retVal = createReadInvocation(id, resourceName); retVal = createReadInvocation(getContext(), id, resourceName);
} }
} else { } else {
IdDt vid = ((IdDt) theArgs[myVersionIdIndex]); IdDt vid = ((IdDt) theArgs[myVersionIdIndex]);
String resourceName = getResourceName(); String resourceName = getResourceName();
retVal = createVReadInvocation(new IdDt(resourceName, id.getIdPart(), vid.getVersionIdPart()), resourceName); retVal = createVReadInvocation(getContext(), new IdDt(resourceName, id.getIdPart(), vid.getVersionIdPart()), resourceName);
} }
for (int idx = 0; idx < theArgs.length; idx++) { for (int idx = 0; idx < theArgs.length; idx++) {
@ -249,20 +249,20 @@ public class ReadMethodBinding extends BaseResourceReturningMethodBinding implem
return mySupportsVersion || myVersionIdIndex != null; return mySupportsVersion || myVersionIdIndex != null;
} }
public static HttpGetClientInvocation createAbsoluteReadInvocation(IIdType theId) { public static HttpGetClientInvocation createAbsoluteReadInvocation(FhirContext theContext, IIdType theId) {
return new HttpGetClientInvocation(theId.toVersionless().getValue()); return new HttpGetClientInvocation(theContext, theId.toVersionless().getValue());
} }
public static HttpGetClientInvocation createAbsoluteVReadInvocation(IIdType theId) { public static HttpGetClientInvocation createAbsoluteVReadInvocation(FhirContext theContext, IIdType theId) {
return new HttpGetClientInvocation(theId.getValue()); return new HttpGetClientInvocation(theContext, theId.getValue());
} }
public static HttpGetClientInvocation createReadInvocation(IIdType theId, String theResourceName) { public static HttpGetClientInvocation createReadInvocation(FhirContext theContext, IIdType theId, String theResourceName) {
return new HttpGetClientInvocation(new IdDt(theResourceName, theId.getIdPart()).getValue()); return new HttpGetClientInvocation(theContext, new IdDt(theResourceName, theId.getIdPart()).getValue());
} }
public static HttpGetClientInvocation createVReadInvocation(IIdType theId, String theResourceName) { public static HttpGetClientInvocation createVReadInvocation(FhirContext theContext, IIdType theId, String theResourceName) {
return new HttpGetClientInvocation(new IdDt(theResourceName, theId.getIdPart(), theId.getVersionIdPart()).getValue()); return new HttpGetClientInvocation(theContext, new IdDt(theResourceName, theId.getIdPart(), theId.getVersionIdPart()).getValue());
} }
@Override @Override

View File

@ -4,6 +4,7 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.Reader; import java.io.Reader;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
/* /*
* #%L * #%L
@ -274,4 +275,9 @@ public abstract class RequestDetails {
mySecondaryOperation = theSecondaryOperation; mySecondaryOperation = theSecondaryOperation;
} }
/**
* Return the charset as defined by the header contenttype. Return null if it is not set.
*/
public abstract Charset getCharset();
} }

View File

@ -340,16 +340,16 @@ public class SearchMethodBinding extends BaseResourceReturningMethodBinding {
case GET: case GET:
default: default:
if (compartmentSearch) { if (compartmentSearch) {
invocation = new HttpGetClientInvocation(theParameters, theResourceName, theId.getIdPart(), theCompartmentName); invocation = new HttpGetClientInvocation(theContext, theParameters, theResourceName, theId.getIdPart(), theCompartmentName);
} else { } else {
invocation = new HttpGetClientInvocation(theParameters, theResourceName); invocation = new HttpGetClientInvocation(theContext, theParameters, theResourceName);
} }
break; break;
case GET_WITH_SEARCH: case GET_WITH_SEARCH:
if (compartmentSearch) { if (compartmentSearch) {
invocation = new HttpGetClientInvocation(theParameters, theResourceName, theId.getIdPart(), theCompartmentName, Constants.PARAM_SEARCH); invocation = new HttpGetClientInvocation(theContext, theParameters, theResourceName, theId.getIdPart(), theCompartmentName, Constants.PARAM_SEARCH);
} else { } else {
invocation = new HttpGetClientInvocation(theParameters, theResourceName, Constants.PARAM_SEARCH); invocation = new HttpGetClientInvocation(theContext, theParameters, theResourceName, Constants.PARAM_SEARCH);
} }
break; break;
case POST: case POST:
@ -456,8 +456,8 @@ public class SearchMethodBinding extends BaseResourceReturningMethodBinding {
} }
public static BaseHttpClientInvocation createSearchInvocation(String theSearchUrl, Map<String, List<String>> theParams) { public static BaseHttpClientInvocation createSearchInvocation(FhirContext theContext, String theSearchUrl, Map<String, List<String>> theParams) {
return new HttpGetClientInvocation(theParams, theSearchUrl); return new HttpGetClientInvocation(theContext, theParams, theSearchUrl);
} }
} }

View File

@ -53,8 +53,8 @@ public class TransactionMethodBinding extends BaseResourceReturningMethodBinding
private int myTransactionParamIndex; private int myTransactionParamIndex;
private ParamStyle myTransactionParamStyle; private ParamStyle myTransactionParamStyle;
public TransactionMethodBinding(Method theMethod, FhirContext theConetxt, Object theProvider) { public TransactionMethodBinding(Method theMethod, FhirContext theContext, Object theProvider) {
super(null, theMethod, theConetxt, theProvider); super(null, theMethod, theContext, theProvider);
myTransactionParamIndex = -1; myTransactionParamIndex = -1;
int index = 0; int index = 0;

View File

@ -20,7 +20,6 @@ package ca.uhn.fhir.rest.param;
* #L% * #L%
*/ */
import static org.apache.commons.lang3.StringUtils.isBlank; import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
@ -35,7 +34,6 @@ import java.util.Map;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.Validate;
import org.apache.http.entity.ContentType;
import org.hl7.fhir.instance.model.api.IBaseBinary; import org.hl7.fhir.instance.model.api.IBaseBinary;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
@ -130,13 +128,7 @@ public class ResourceParameter implements IParameter {
} }
public static Charset determineRequestCharset(RequestDetails theRequest) { public static Charset determineRequestCharset(RequestDetails theRequest) {
String ct = theRequest.getHeader(Constants.HEADER_CONTENT_TYPE); Charset charset = theRequest.getCharset();
Charset charset = null;
if (isNotBlank(ct)) {
ContentType parsedCt = ContentType.parse(ct);
charset = parsedCt.getCharset();
}
if (charset == null) { if (charset == null) {
charset = Charset.forName("UTF-8"); charset = Charset.forName("UTF-8");
} }

View File

@ -43,7 +43,6 @@ import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.utils.DateUtils;
import org.hl7.fhir.instance.model.api.IAnyResource; import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBaseBinary; import org.hl7.fhir.instance.model.api.IBaseBinary;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
@ -69,6 +68,7 @@ import ca.uhn.fhir.rest.method.RequestDetails;
import ca.uhn.fhir.rest.method.SummaryEnumParameter; import ca.uhn.fhir.rest.method.SummaryEnumParameter;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.util.DateUtils;
public class RestfulServerUtils { public class RestfulServerUtils {
static final Pattern ACCEPT_HEADER_PATTERN = Pattern.compile("\\s*([a-zA-Z0-9+.*/-]+)\\s*(;\\s*([a-zA-Z]+)\\s*=\\s*([a-zA-Z0-9.]+)\\s*)?(,?)"); static final Pattern ACCEPT_HEADER_PATTERN = Pattern.compile("\\s*([a-zA-Z0-9+.*/-]+)\\s*(;\\s*([a-zA-Z]+)\\s*=\\s*([a-zA-Z0-9.]+)\\s*)?(,?)");

View File

@ -1,7 +1,5 @@
package ca.uhn.fhir.rest.server.servlet; package ca.uhn.fhir.rest.server.servlet;
import java.io.ByteArrayInputStream;
/* /*
* #%L * #%L
* HAPI FHIR - Core Library * HAPI FHIR - Core Library
@ -21,10 +19,13 @@ import java.io.ByteArrayInputStream;
* limitations under the License. * limitations under the License.
* #L% * #L%
*/ */
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.Reader; import java.io.Reader;
import java.nio.charset.Charset;
import java.util.Collections; import java.util.Collections;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.HashMap; import java.util.HashMap;
@ -37,6 +38,7 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.http.entity.ContentType;
import ca.uhn.fhir.context.ConfigurationException; import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.rest.api.RequestTypeEnum; import ca.uhn.fhir.rest.api.RequestTypeEnum;
@ -176,4 +178,16 @@ public class ServletRequestDetails extends RequestDetails {
return retVal; return retVal;
} }
@Override
public Charset getCharset() {
String ct = getHeader(Constants.HEADER_CONTENT_TYPE);
Charset charset = null;
if (isNotBlank(ct)) {
ContentType parsedCt = ContentType.parse(ct);
charset = parsedCt.getCharset();
}
return charset;
}
} }

View File

@ -0,0 +1,254 @@
package ca.uhn.fhir.util;
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
import java.lang.ref.SoftReference;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;
/**
* A utility class for parsing and formatting HTTP dates as used in cookies and
* other headers. This class handles dates as defined by RFC 2616 section
* 3.3.1 as well as some other common non-standard formats.
*
* @since 4.3
*/
public final class DateUtils {
/**
* Date format pattern used to parse HTTP date headers in RFC 1123 format.
*/
public static final String PATTERN_RFC1123 = "EEE, dd MMM yyyy HH:mm:ss zzz";
/**
* Date format pattern used to parse HTTP date headers in RFC 1036 format.
*/
public static final String PATTERN_RFC1036 = "EEE, dd-MMM-yy HH:mm:ss zzz";
/**
* Date format pattern used to parse HTTP date headers in ANSI C
* {@code asctime()} format.
*/
public static final String PATTERN_ASCTIME = "EEE MMM d HH:mm:ss yyyy";
private static final String[] DEFAULT_PATTERNS = new String[] {
PATTERN_RFC1123,
PATTERN_RFC1036,
PATTERN_ASCTIME
};
private static final Date DEFAULT_TWO_DIGIT_YEAR_START;
public static final TimeZone GMT = TimeZone.getTimeZone("GMT");
static {
final Calendar calendar = Calendar.getInstance();
calendar.setTimeZone(GMT);
calendar.set(2000, Calendar.JANUARY, 1, 0, 0, 0);
calendar.set(Calendar.MILLISECOND, 0);
DEFAULT_TWO_DIGIT_YEAR_START = calendar.getTime();
}
/**
* Parses a date value. The formats used for parsing the date value are retrieved from
* the default http params.
*
* @param dateValue the date value to parse
*
* @return the parsed date or null if input could not be parsed
*/
public static Date parseDate(final String dateValue) {
return parseDate(dateValue, null, null);
}
/**
* Parses the date value using the given date formats.
*
* @param dateValue the date value to parse
* @param dateFormats the date formats to use
*
* @return the parsed date or null if input could not be parsed
*/
public static Date parseDate(final String dateValue, final String[] dateFormats) {
return parseDate(dateValue, dateFormats, null);
}
/**
* Parses the date value using the given date formats.
*
* @param dateValue the date value to parse
* @param dateFormats the date formats to use
* @param startDate During parsing, two digit years will be placed in the range
* {@code startDate} to {@code startDate + 100 years}. This value may
* be {@code null}. When {@code null} is given as a parameter, year
* {@code 2000} will be used.
*
* @return the parsed date or null if input could not be parsed
*/
public static Date parseDate(
final String dateValue,
final String[] dateFormats,
final Date startDate) {
notNull(dateValue, "Date value");
final String[] localDateFormats = dateFormats != null ? dateFormats : DEFAULT_PATTERNS;
final Date localStartDate = startDate != null ? startDate : DEFAULT_TWO_DIGIT_YEAR_START;
String v = dateValue;
// trim single quotes around date if present
// see issue #5279
if (v.length() > 1 && v.startsWith("'") && v.endsWith("'")) {
v = v.substring (1, v.length() - 1);
}
for (final String dateFormat : localDateFormats) {
final SimpleDateFormat dateParser = DateFormatHolder.formatFor(dateFormat);
dateParser.set2DigitYearStart(localStartDate);
final ParsePosition pos = new ParsePosition(0);
final Date result = dateParser.parse(v, pos);
if (pos.getIndex() != 0) {
return result;
}
}
return null;
}
/**
* Formats the given date according to the RFC 1123 pattern.
*
* @param date The date to format.
* @return An RFC 1123 formatted date string.
*
* @see #PATTERN_RFC1123
*/
public static String formatDate(final Date date) {
return formatDate(date, PATTERN_RFC1123);
}
/**
* Formats the given date according to the specified pattern. The pattern
* must conform to that used by the {@link SimpleDateFormat simple date
* format} class.
*
* @param date The date to format.
* @param pattern The pattern to use for formatting the date.
* @return A formatted date string.
*
* @throws IllegalArgumentException If the given date pattern is invalid.
*
* @see SimpleDateFormat
*/
public static String formatDate(final Date date, final String pattern) {
notNull(date, "Date");
notNull(pattern, "Pattern");
final SimpleDateFormat formatter = DateFormatHolder.formatFor(pattern);
return formatter.format(date);
}
public static <T> T notNull(final T argument, final String name) {
if (argument == null) {
throw new IllegalArgumentException(name + " may not be null");
}
return argument;
}
/**
* Clears thread-local variable containing {@link java.text.DateFormat} cache.
*
* @since 4.3
*/
public static void clearThreadLocal() {
DateFormatHolder.clearThreadLocal();
}
/** This class should not be instantiated. */
private DateUtils() {
}
/**
* A factory for {@link SimpleDateFormat}s. The instances are stored in a
* threadlocal way because SimpleDateFormat is not threadsafe as noted in
* {@link SimpleDateFormat its javadoc}.
*
*/
final static class DateFormatHolder {
private static final ThreadLocal<SoftReference<Map<String, SimpleDateFormat>>>
THREADLOCAL_FORMATS = new ThreadLocal<SoftReference<Map<String, SimpleDateFormat>>>() {
@Override
protected SoftReference<Map<String, SimpleDateFormat>> initialValue() {
return new SoftReference<Map<String, SimpleDateFormat>>(
new HashMap<String, SimpleDateFormat>());
}
};
/**
* creates a {@link SimpleDateFormat} for the requested format string.
*
* @param pattern
* a non-{@code null} format String according to
* {@link SimpleDateFormat}. The format is not checked against
* {@code null} since all paths go through
* {@link DateUtils}.
* @return the requested format. This simple dateformat should not be used
* to {@link SimpleDateFormat#applyPattern(String) apply} to a
* different pattern.
*/
public static SimpleDateFormat formatFor(final String pattern) {
final SoftReference<Map<String, SimpleDateFormat>> ref = THREADLOCAL_FORMATS.get();
Map<String, SimpleDateFormat> formats = ref.get();
if (formats == null) {
formats = new HashMap<String, SimpleDateFormat>();
THREADLOCAL_FORMATS.set(
new SoftReference<Map<String, SimpleDateFormat>>(formats));
}
SimpleDateFormat format = formats.get(pattern);
if (format == null) {
format = new SimpleDateFormat(pattern, Locale.US);
format.setTimeZone(TimeZone.getTimeZone("GMT"));
formats.put(pattern, format);
}
return format;
}
public static void clearThreadLocal() {
THREADLOCAL_FORMATS.remove();
}
}
}

View File

@ -208,7 +208,7 @@
<artifactItem> <artifactItem>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-cli-jpaserver</artifactId> <artifactId>hapi-fhir-cli-jpaserver</artifactId>
<version>1.4-SNAPSHOT</version> <version>1.5-SNAPSHOT</version>
<type>war</type> <type>war</type>
<overWrite>true</overWrite> <overWrite>true</overWrite>
<outputDirectory>target/classes</outputDirectory> <outputDirectory>target/classes</outputDirectory>

View File

@ -53,7 +53,7 @@ import ca.uhn.fhir.model.dstu2.valueset.HTTPVerbEnum;
import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.parser.DataFormatException; import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.rest.client.IGenericClient; import ca.uhn.fhir.rest.client.IGenericClient;
import ca.uhn.fhir.rest.client.interceptor.GZipContentInterceptor; import ca.uhn.fhir.rest.client.apache.GZipContentInterceptor;
import ca.uhn.fhir.util.ResourceReferenceInfo; import ca.uhn.fhir.util.ResourceReferenceInfo;
public class ExampleDataUploader extends BaseCommand { public class ExampleDataUploader extends BaseCommand {

View File

@ -24,6 +24,14 @@
<artifactId>commons-logging</artifactId> <artifactId>commons-logging</artifactId>
<groupId>commons-logging</groupId> <groupId>commons-logging</groupId>
</exclusion> </exclusion>
<exclusion>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
</exclusion>
</exclusions> </exclusions>
</dependency> </dependency>
<!-- conformance profile --> <!-- conformance profile -->

View File

@ -0,0 +1,160 @@
package ca.uhn.fhir.jaxrs.client;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2016 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.util.List;
import java.util.Map;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.Invocation.Builder;
import javax.ws.rs.core.Form;
import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.MultivaluedMap;
import org.hl7.fhir.instance.model.api.IBaseBinary;
import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.client.BaseHttpClientInvocation;
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.server.Constants;
import ca.uhn.fhir.rest.server.EncodingEnum;
import ca.uhn.fhir.util.VersionUtil;
/**
* A Http Request based on JaxRs. This is an adapter around the class
* {@link javax.ws.rs.client.Client Client}
*
* @author Peter Van Houte | peter.vanhoute@agfa.com | Agfa Healthcare
*/
public class JaxRsHttpClient implements IHttpClient {
private Client myClient;
private List<Header> myHeaders;
private StringBuilder myUrl;
private Map<String, List<String>> myIfNoneExistParams;
private String myIfNoneExistString;
private RequestTypeEnum myRequestType;
public JaxRsHttpClient(Client theClient, StringBuilder theUrl, Map<String, List<String>> theIfNoneExistParams, String theIfNoneExistString,
RequestTypeEnum theRequestType, List<Header> theHeaders) {
this.myClient = theClient;
this.myUrl = theUrl;
this.myIfNoneExistParams = theIfNoneExistParams;
this.myIfNoneExistString = theIfNoneExistString;
this.myRequestType = theRequestType;
this.myHeaders = theHeaders;
}
@Override
public IHttpRequest createByteRequest(String theContents, String theContentType, EncodingEnum theEncoding) {
Entity<String> entity = Entity.entity(theContents, theContentType + Constants.HEADER_SUFFIX_CT_UTF_8);
JaxRsHttpRequest retVal = createHttpRequest(entity);
addHeadersToRequest(retVal, theEncoding);
retVal.addHeader(Constants.HEADER_CONTENT_TYPE, theContentType + Constants.HEADER_SUFFIX_CT_UTF_8);
return retVal;
}
@Override
public IHttpRequest createParamRequest(Map<String, List<String>> theParams, EncodingEnum theEncoding) {
MultivaluedMap<String, String> map = new MultivaluedHashMap<String, String>();
for (Map.Entry<String, List<String>> nextParam : theParams.entrySet()) {
List<String> value = nextParam.getValue();
for (String s : value) {
map.add(nextParam.getKey(), s);
}
}
Entity<Form> entity = Entity.form(map);
JaxRsHttpRequest retVal = createHttpRequest(entity);
// addHeadersToRequest(retVal, encoding);
return retVal;
}
@Override
public IHttpRequest createBinaryRequest(IBaseBinary theBinary) {
Entity<String> entity = Entity.entity(theBinary.getContentAsBase64(), theBinary.getContentType());
JaxRsHttpRequest retVal = createHttpRequest(entity);
return retVal;
}
@Override
public IHttpRequest createGetRequest(EncodingEnum theEncoding) {
JaxRsHttpRequest result = createHttpRequest(null);
addHeadersToRequest(result, theEncoding);
return result;
}
public void addHeadersToRequest(JaxRsHttpRequest theHttpRequest, EncodingEnum theEncoding) {
if (myHeaders != null) {
for (Header next : myHeaders) {
theHttpRequest.addHeader(next.getName(), next.getValue());
}
}
theHttpRequest.addHeader("User-Agent", "HAPI-FHIR/" + VersionUtil.getVersion() + " (FHIR Client)");
theHttpRequest.addHeader("Accept-Charset", "utf-8");
Builder request = theHttpRequest.getRequest();
request.acceptEncoding("gzip");
if (theEncoding == null) {
request.accept(Constants.HEADER_ACCEPT_VALUE_ALL);
} else if (theEncoding == EncodingEnum.JSON) {
request.accept(Constants.CT_FHIR_JSON);
} else if (theEncoding == EncodingEnum.XML) {
request.accept(Constants.CT_FHIR_XML);
}
}
private JaxRsHttpRequest createHttpRequest(Entity<?> entity) {
Builder request = myClient.target(myUrl.toString()).request();
JaxRsHttpRequest result = new JaxRsHttpRequest(request, myRequestType, entity);
addHeaderIfNoneExist(result);
return result;
}
private void addHeaderIfNoneExist(IHttpRequest result) {
if (myIfNoneExistParams != null) {
StringBuilder b = newHeaderBuilder(myUrl);
BaseHttpClientInvocation.appendExtraParamsWithQuestionMark(myIfNoneExistParams, b, b.indexOf("?") == -1);
result.addHeader(Constants.HEADER_IF_NONE_EXIST, b.toString());
}
if (myIfNoneExistString != null) {
StringBuilder b = newHeaderBuilder(myUrl);
b.append(b.indexOf("?") == -1 ? '?' : '&');
b.append(myIfNoneExistString.substring(myIfNoneExistString.indexOf('?') + 1));
result.addHeader(Constants.HEADER_IF_NONE_EXIST, b.toString());
}
}
private StringBuilder newHeaderBuilder(StringBuilder theUrlBase) {
StringBuilder b = new StringBuilder();
b.append(theUrlBase);
if (theUrlBase.length() > 0 && theUrlBase.charAt(theUrlBase.length() - 1) == '/') {
b.deleteCharAt(b.length() - 1);
}
return b;
}
}

View File

@ -0,0 +1,106 @@
package ca.uhn.fhir.jaxrs.client;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2016 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.Invocation;
import javax.ws.rs.core.Response;
import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.client.api.IHttpRequest;
import ca.uhn.fhir.rest.client.api.IHttpResponse;
/**
* A Http Request based on JaxRs. This is an adapter around the class
* {@link javax.ws.rs.client.Invocation Invocation}
*
* @author Peter Van Houte | peter.vanhoute@agfa.com | Agfa Healthcare
*/
public class JaxRsHttpRequest implements IHttpRequest {
private Invocation.Builder myRequest;
private RequestTypeEnum myRequestType;
private Entity<?> myEntity;
private final Map<String, List<String>> myHeaders = new HashMap<String, List<String>>();
public JaxRsHttpRequest(Invocation.Builder theRequest, RequestTypeEnum theRequestType, Entity<?> theEntity) {
this.myRequest = theRequest;
this.myRequestType = theRequestType;
this.myEntity = theEntity;
}
@Override
public void addHeader(String theName, String theValue) {
if (!myHeaders.containsKey(theName)) {
myHeaders.put(theName, new LinkedList<String>());
}
myHeaders.get(theName).add(theValue);
getRequest().header(theName, theValue);
}
/**
* Get the Request
* @return the Request
*/
public Invocation.Builder getRequest() {
return myRequest;
}
/**
* Get the Request Type
* @return the request type
*/
public RequestTypeEnum getRequestType() {
return myRequestType == null ? RequestTypeEnum.GET : myRequestType;
}
/**
* Get the Entity
* @return the entity
*/
public Entity<?> getEntity() {
return myEntity;
}
@Override
public IHttpResponse execute() {
Invocation invocation = getRequest().build(getRequestType().name(), getEntity());
Response response = invocation.invoke();
return new JaxRsHttpResponse(response);
}
@Override
public Map<String, List<String>> getAllHeaders() {
return this.myHeaders;
}
@Override
public String getRequestBodyFromStream() {
// not supported
return null;
}
}

View File

@ -0,0 +1,111 @@
package ca.uhn.fhir.jaxrs.client;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2016 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.io.InputStream;
import java.io.Reader;
import java.io.StringReader;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import ca.uhn.fhir.rest.client.api.IHttpResponse;
/**
* A Http Response based on JaxRs. This is an adapter around the class {@link javax.ws.rs.core.Response Response}
* @author Peter Van Houte | peter.vanhoute@agfa.com | Agfa Healthcare
*/
public class JaxRsHttpResponse implements IHttpResponse {
private final Response myResponse;
private boolean myBufferedEntity = false;
public JaxRsHttpResponse(Response theResponse) {
this.myResponse = theResponse;
}
@Override
public Response getResponse() {
return myResponse;
}
@Override
public int getStatus() {
return myResponse.getStatus();
}
@Override
public String getMimeType() {
MediaType mediaType = myResponse.getMediaType();
//Keep only type and subtype and do not include the parameters such as charset
return new MediaType(mediaType.getType(), mediaType.getSubtype()).toString();
}
@Override
public Map<String, List<String>> getAllHeaders() {
Map<String, List<String>> theHeaders = new ConcurrentHashMap<String, List<String>>();
for (Entry<String, List<String>> iterable_element : myResponse.getStringHeaders().entrySet()) {
theHeaders.put(iterable_element.getKey().toLowerCase(), iterable_element.getValue());
}
return theHeaders;
}
@Override
public String getStatusInfo() {
return myResponse.getStatusInfo().getReasonPhrase();
}
@Override
public Reader createReader() {
if (!myBufferedEntity && !myResponse.hasEntity()) {
return new StringReader("");
} else {
return new StringReader(myResponse.readEntity(String.class));
}
}
@Override
public InputStream readEntity() {
return myResponse.readEntity(java.io.InputStream.class);
}
@Override
public void bufferEntitity() {
if(!myBufferedEntity && myResponse.hasEntity()) {
myBufferedEntity = true;
myResponse.bufferEntity();
} else {
myResponse.bufferEntity();
}
}
@Override
public void close() {
// automatically done by jax-rs
}
}

View File

@ -0,0 +1,97 @@
package ca.uhn.fhir.jaxrs.client;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2016 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.client.RestfulClientFactory;
import ca.uhn.fhir.rest.client.api.Header;
import ca.uhn.fhir.rest.client.api.IHttpClient;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import java.util.List;
import java.util.Map;
/**
* A Restful Client Factory, based on Jax Rs
*
* @author Peter Van Houte | peter.vanhoute@agfa.com | Agfa Healthcare
*/
public class JaxRsRestfulClientFactory extends RestfulClientFactory {
private Client myNativeClient;
/**
* Constructor
*/
public JaxRsRestfulClientFactory() {
}
/**
* Constructor
* @param theFhirContext The context
*/
public JaxRsRestfulClientFactory(FhirContext theFhirContext) {
super(theFhirContext);
}
public synchronized Client getNativeClientClient() {
if (myNativeClient == null) {
ClientBuilder builder = ClientBuilder.newBuilder();
myNativeClient = builder.build();
}
return myNativeClient;
}
@Override
public IHttpClient getHttpClient(StringBuilder url, Map<String, List<String>> theIfNoneExistParams,
String theIfNoneExistString, RequestTypeEnum theRequestType, List<Header> theHeaders) {
return new JaxRsHttpClient(getNativeClientClient(), url, theIfNoneExistParams, theIfNoneExistString, theRequestType,
theHeaders);
}
@Override
public void setProxy(String theHost, Integer thePort) {
throw new UnsupportedOperationException("Proxies are not supported yet");
}
/**
* Only accept clients of type javax.ws.rs.client.Client
* @param theHttpClient
*/
@Override
public synchronized void setHttpClient(Object theHttpClient) {
this.myNativeClient = (Client) theHttpClient;
}
@Override
protected JaxRsHttpClient getHttpClient(String theServerBase) {
return new JaxRsHttpClient(getNativeClientClient(), new StringBuilder(theServerBase), null, null, null, null);
}
@Override
protected void resetHttpClient() {
this.myNativeClient = null;
}
}

View File

@ -23,10 +23,12 @@ package ca.uhn.fhir.jaxrs.server.util;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.Reader; import java.io.Reader;
import java.nio.charset.Charset;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@ -149,8 +151,8 @@ public class JaxRsRequest extends RequestDetails {
} }
} }
private String theResourceString; private String myResourceString;
private HttpHeaders headers; private HttpHeaders myHeaders;
private AbstractJaxRsProvider myServer; private AbstractJaxRsProvider myServer;
/** /**
@ -162,8 +164,8 @@ public class JaxRsRequest extends RequestDetails {
*/ */
public JaxRsRequest(AbstractJaxRsProvider server, String resourceString, RequestTypeEnum requestType, public JaxRsRequest(AbstractJaxRsProvider server, String resourceString, RequestTypeEnum requestType,
RestOperationTypeEnum restOperation) { RestOperationTypeEnum restOperation) {
this.headers = server.getHeaders(); this.myHeaders = server.getHeaders();
this.theResourceString = resourceString; this.myResourceString = resourceString;
this.setRestOperationType(restOperation); this.setRestOperationType(restOperation);
setServer(server); setServer(server);
setFhirServerBase(server.getBaseForServer()); setFhirServerBase(server.getBaseForServer());
@ -192,7 +194,7 @@ public class JaxRsRequest extends RequestDetails {
@Override @Override
public List<String> getHeaders(String name) { public List<String> getHeaders(String name) {
List<String> requestHeader = headers.getRequestHeader(name); List<String> requestHeader = myHeaders.getRequestHeader(name);
return requestHeader == null ? Collections.<String> emptyList() : requestHeader; return requestHeader == null ? Collections.<String> emptyList() : requestHeader;
} }
@ -203,7 +205,7 @@ public class JaxRsRequest extends RequestDetails {
@Override @Override
protected byte[] getByteStreamRequestContents() { protected byte[] getByteStreamRequestContents() {
return StringUtils.defaultIfEmpty(theResourceString, "") return StringUtils.defaultIfEmpty(myResourceString, "")
.getBytes(ResourceParameter.determineRequestCharset(this)); .getBytes(ResourceParameter.determineRequestCharset(this));
} }
@ -226,4 +228,18 @@ public class JaxRsRequest extends RequestDetails {
// not yet implemented // not yet implemented
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override
public Charset getCharset() {
String charset = null;
if(myHeaders.getMediaType() != null && myHeaders.getMediaType().getParameters() != null) {
charset = myHeaders.getMediaType().getParameters().get(MediaType.CHARSET_PARAMETER);
}
if(charset != null) {
return Charset.forName(charset);
} else {
return null;
}
}
} }

View File

@ -38,6 +38,7 @@ import ca.uhn.fhir.jaxrs.server.test.RandomServerPortProvider;
import ca.uhn.fhir.jaxrs.server.test.TestJaxRsConformanceRestProvider; import ca.uhn.fhir.jaxrs.server.test.TestJaxRsConformanceRestProvider;
import ca.uhn.fhir.jaxrs.server.test.TestJaxRsMockPageProvider; import ca.uhn.fhir.jaxrs.server.test.TestJaxRsMockPageProvider;
import ca.uhn.fhir.jaxrs.server.test.TestJaxRsMockPatientRestProvider; import ca.uhn.fhir.jaxrs.server.test.TestJaxRsMockPatientRestProvider;
import ca.uhn.fhir.jaxrs.client.JaxRsRestfulClientFactory;
import ca.uhn.fhir.jaxrs.server.interceptor.JaxRsExceptionInterceptor; import ca.uhn.fhir.jaxrs.server.interceptor.JaxRsExceptionInterceptor;
import ca.uhn.fhir.model.api.BundleEntry; import ca.uhn.fhir.model.api.BundleEntry;
import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.IResource;
@ -104,6 +105,7 @@ public class AbstractJaxRsResourceProviderTest {
jettyServer.start(); jettyServer.start();
ourCtx.setRestfulClientFactory(new JaxRsRestfulClientFactory(ourCtx));
ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER); ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
ourCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000); ourCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000);
serverBase = "http://localhost:" + ourPort + "/"; serverBase = "http://localhost:" + ourPort + "/";

View File

@ -1,7 +1,6 @@
package ca.uhn.fhir.jaxrs.server.example; package ca.uhn.fhir.jaxrs.server.example;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedList; import java.util.LinkedList;

View File

@ -18,6 +18,7 @@ import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jaxrs.client.JaxRsRestfulClientFactory;
import ca.uhn.fhir.model.api.BundleEntry; import ca.uhn.fhir.model.api.BundleEntry;
import ca.uhn.fhir.model.dstu2.composite.HumanNameDt; import ca.uhn.fhir.model.dstu2.composite.HumanNameDt;
import ca.uhn.fhir.model.dstu2.resource.Bundle; import ca.uhn.fhir.model.dstu2.resource.Bundle;
@ -66,6 +67,7 @@ public class JaxRsPatientProviderTest {
//@formatter:on //@formatter:on
jettyServer.start(); jettyServer.start();
ourCtx.setRestfulClientFactory(new JaxRsRestfulClientFactory(ourCtx));
ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER); ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
ourCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000); ourCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000);
client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/"); client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/");

View File

@ -24,12 +24,14 @@ import java.util.Set;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.commons.io.input.ReaderInputStream; import org.apache.commons.io.input.ReaderInputStream;
import org.apache.http.Header; import org.apache.http.Header;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
import org.apache.http.ProtocolVersion; import org.apache.http.ProtocolVersion;
import org.apache.http.client.HttpClient; import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut; import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.message.BasicHeader; import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicStatusLine; import org.apache.http.message.BasicStatusLine;
@ -66,6 +68,7 @@ import ca.uhn.fhir.rest.annotation.RequiredParam;
import ca.uhn.fhir.rest.annotation.Search; import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.api.MethodOutcome; import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.SummaryEnum; import ca.uhn.fhir.rest.api.SummaryEnum;
import ca.uhn.fhir.rest.client.apache.ApacheHttpRequest;
import ca.uhn.fhir.rest.client.api.IBasicClient; import ca.uhn.fhir.rest.client.api.IBasicClient;
import ca.uhn.fhir.rest.client.interceptor.CapturingInterceptor; import ca.uhn.fhir.rest.client.interceptor.CapturingInterceptor;
import ca.uhn.fhir.rest.param.CompositeParam; import ca.uhn.fhir.rest.param.CompositeParam;
@ -150,7 +153,7 @@ public class ClientDstu1Test {
MethodOutcome response = client.createPatient(patient); MethodOutcome response = client.createPatient(patient);
assertEquals(interceptor.getLastRequest().getURI().toASCIIString(), "http://foo/Patient"); assertEquals(((ApacheHttpRequest) interceptor.getLastRequest()).getApacheRequest().getURI().toASCIIString(), "http://foo/Patient");
assertEquals(HttpPost.class, capt.getValue().getClass()); assertEquals(HttpPost.class, capt.getValue().getClass());
HttpPost post = (HttpPost) capt.getValue(); HttpPost post = (HttpPost) capt.getValue();

View File

@ -82,7 +82,7 @@ public class LoggingInterceptorTest {
public boolean matches(final Object argument) { public boolean matches(final Object argument) {
String formattedMessage = ((LoggingEvent) argument).getFormattedMessage(); String formattedMessage = ((LoggingEvent) argument).getFormattedMessage();
System.out.println("Verifying: " + formattedMessage); System.out.println("Verifying: " + formattedMessage);
return formattedMessage.replace("; ", ";").replace("UTF", "utf").contains("Content-Type: application/xml+fhir;charset=utf-8"); return formattedMessage.replace("; ", ";").toLowerCase().contains("Content-Type: application/xml+fhir;charset=utf-8".toLowerCase());
} }
})); }));
} }

View File

@ -20,6 +20,7 @@ import ca.uhn.fhir.rest.annotation.Create;
import ca.uhn.fhir.rest.annotation.ResourceParam; import ca.uhn.fhir.rest.annotation.ResourceParam;
import ca.uhn.fhir.rest.api.MethodOutcome; import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.client.IGenericClient; import ca.uhn.fhir.rest.client.IGenericClient;
import ca.uhn.fhir.rest.client.apache.GZipContentInterceptor;
import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.FifoMemoryPagingProvider; import ca.uhn.fhir.rest.server.FifoMemoryPagingProvider;
import ca.uhn.fhir.rest.server.IResourceProvider; import ca.uhn.fhir.rest.server.IResourceProvider;

View File

@ -52,6 +52,8 @@ import ca.uhn.fhir.model.primitive.DecimalDt;
import ca.uhn.fhir.narrative.INarrativeGenerator; import ca.uhn.fhir.narrative.INarrativeGenerator;
import ca.uhn.fhir.rest.client.GenericClient; import ca.uhn.fhir.rest.client.GenericClient;
import ca.uhn.fhir.rest.client.IClientInterceptor; import ca.uhn.fhir.rest.client.IClientInterceptor;
import ca.uhn.fhir.rest.client.api.IHttpRequest;
import ca.uhn.fhir.rest.client.api.IHttpResponse;
import ca.uhn.fhir.rest.server.EncodingEnum; import ca.uhn.fhir.rest.server.EncodingEnum;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.to.model.HomeRequest; import ca.uhn.fhir.to.model.HomeRequest;
@ -290,7 +292,7 @@ public class BaseController {
returnsResource = ResultType.NONE; returnsResource = ResultType.NONE;
ourLog.warn("Failed to invoke server", e); ourLog.warn("Failed to invoke server", e);
if (theClient.getLastResponse() == null) { if (e != null) {
theModel.put("errorMsg", "Error: " + e.getMessage()); theModel.put("errorMsg", "Error: " + e.getMessage());
} }
@ -653,17 +655,17 @@ public class BaseController {
} }
@Override @Override
public void interceptRequest(HttpRequestBase theRequest) { public void interceptRequest(IHttpRequest theRequest) {
assert myLastRequest == null; assert myLastRequest == null;
myLastRequest = theRequest; myLastRequest = (HttpRequestBase) theRequest;
} }
@Override @Override
public void interceptResponse(HttpResponse theResponse) throws IOException { public void interceptResponse(IHttpResponse theResponse) throws IOException {
assert myLastResponse == null; assert myLastResponse == null;
myLastResponse = theResponse; myLastResponse = (HttpResponse) theResponse;
HttpEntity respEntity = theResponse.getEntity(); HttpEntity respEntity = myLastResponse.getEntity();
if (respEntity != null) { if (respEntity != null) {
final byte[] bytes; final byte[] bytes;
try { try {
@ -673,7 +675,7 @@ public class BaseController {
} }
myResponseBody = new String(bytes, "UTF-8"); myResponseBody = new String(bytes, "UTF-8");
theResponse.setEntity(new MyEntityWrapper(respEntity, bytes)); myLastResponse.setEntity(new MyEntityWrapper(respEntity, bytes));
} }
} }

View File

@ -15,6 +15,8 @@ import ca.uhn.fhir.rest.api.SummaryEnum;
import ca.uhn.fhir.rest.client.GenericClient; import ca.uhn.fhir.rest.client.GenericClient;
import ca.uhn.fhir.rest.client.IClientInterceptor; import ca.uhn.fhir.rest.client.IClientInterceptor;
import ca.uhn.fhir.rest.client.ServerValidationModeEnum; import ca.uhn.fhir.rest.client.ServerValidationModeEnum;
import ca.uhn.fhir.rest.client.api.IHttpRequest;
import ca.uhn.fhir.rest.client.api.IHttpResponse;
import ca.uhn.fhir.rest.server.EncodingEnum; import ca.uhn.fhir.rest.server.EncodingEnum;
import ca.uhn.fhir.rest.server.IncomingRequestAddressStrategy; import ca.uhn.fhir.rest.server.IncomingRequestAddressStrategy;
import ca.uhn.fhir.to.Controller; import ca.uhn.fhir.to.Controller;
@ -163,12 +165,12 @@ public class HomeRequest {
retVal.registerInterceptor(new IClientInterceptor() { retVal.registerInterceptor(new IClientInterceptor() {
@Override @Override
public void interceptResponse(HttpResponse theRequest) { public void interceptResponse(IHttpResponse theRequest) {
// nothing // nothing
} }
@Override @Override
public void interceptRequest(HttpRequestBase theRequest) { public void interceptRequest(IHttpRequest theRequest) {
if (isNotBlank(remoteAddr)) { if (isNotBlank(remoteAddr)) {
theRequest.addHeader("x-forwarded-for", remoteAddr); theRequest.addHeader("x-forwarded-for", remoteAddr);
} }