Fix #88 - Client should check which FHIR version the server implements and fail if it is incorrect for the client

This commit is contained in:
jamesagnew 2015-01-24 14:51:47 +01:00
parent aa8684c977
commit e19e96db28
30 changed files with 553 additions and 148 deletions

View File

@ -27,20 +27,38 @@ public enum FhirVersionEnum {
/*
* ***********************
* Don't sort this type!!!
* Don't auto-sort this type!!!
*
* Or more accurately, entries should be sorted from OLDEST FHIR release
* to NEWEST FHIR release instead of alphabetically
* ***********************
*/
DSTU1("ca.uhn.fhir.model.dstu.FhirDstu1"),
DSTU1("ca.uhn.fhir.model.dstu.FhirDstu1", null),
DEV("ca.uhn.fhir.model.dev.FhirDev");
DSTU2("ca.uhn.fhir.model.dstu.FhirDev", null),
DEV("ca.uhn.fhir.model.dev.FhirDev", DSTU2);
private final String myVersionClass;
private final FhirVersionEnum myEquivalent;
private volatile Boolean myPresentOnClasspath;
private volatile IFhirVersion myVersionImplementation;
FhirVersionEnum(String theVersionClass) {
FhirVersionEnum(String theVersionClass, FhirVersionEnum theEquivalent) {
myVersionClass = theVersionClass;
myEquivalent = theEquivalent;
}
public boolean isEquivalentTo(FhirVersionEnum theVersion) {
if (this.equals(theVersion)) {
return true;
}
if (myEquivalent != null) {
return myEquivalent.equals(theVersion);
}
return false;
}
public boolean isNewerThan(FhirVersionEnum theVersion) {

View File

@ -22,6 +22,7 @@ package ca.uhn.fhir.model.base.resource;
import ca.uhn.fhir.model.api.BaseResource;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.StringDt;
//@ResourceDef(name="Conformance")
@ -30,5 +31,7 @@ public abstract class BaseConformance extends BaseResource implements IResource
public abstract StringDt getDescriptionElement();
public abstract StringDt getPublisherElement();
public abstract IdDt getFhirVersionElement();
}

View File

@ -36,7 +36,7 @@ import ca.uhn.fhir.rest.client.api.IBasicClient;
/**
* @deprecated Use {@link ca.uhn.fhir.rest.client.interceptor.BasicAuthInterceptor} instead. Note that that class is a HAPI client interceptor instead of being a commons-httpclient interceptor, so you register it to your client instance once it's created using {@link IGenericClient#registerInterceptor(IClientInterceptor)} or {@link IBasicClient#registerInterceptor(IClientInterceptor)} instead
* @deprecated Use {@link ca.uhn.fhir.rest.client.interceptor.BasicAuthInterceptor} instead. Note that BasicAuthInterceptor class is a HAPI client interceptor instead of being a commons-httpclient interceptor, so you register it to your client instance once it's created using {@link IGenericClient#registerInterceptor(IClientInterceptor)} or {@link IBasicClient#registerInterceptor(IClientInterceptor)} instead
*/
public class HttpBasicAuthInterceptor implements HttpRequestInterceptor {

View File

@ -27,6 +27,70 @@ import ca.uhn.fhir.rest.client.api.IRestfulClient;
public interface IRestfulClientFactory {
/**
* Default value for {@link #getConnectTimeout()}
*/
public static final int DEFAULT_CONNECT_TIMEOUT = 10000;
/**
* Default value for {@link #getConnectionRequestTimeout()}
*/
public static final int DEFAULT_CONNECTION_REQUEST_TIMEOUT = 10000;
/**
* Default value for {@link #getServerValidationModeEnum()}
*/
public static final ServerValidationModeEnum DEFAULT_SERVER_VALIDATION_MODE = ServerValidationModeEnum.ONCE;
/**
* Default value for {@link #getSocketTimeout()}
*/
public static final int DEFAULT_SOCKET_TIMEOUT = 10000;
/**
* Gets the connection request timeout, in milliseconds. This is the amount of time that the HTTPClient connection
* pool may wait for an available connection before failing. This setting typically does not need to be adjusted.
* <p>
* The default value for this setting is defined by {@link #DEFAULT_CONNECTION_REQUEST_TIMEOUT}
* </p>
*/
int getConnectionRequestTimeout();
/**
* Gets the connect timeout, in milliseconds. This is the amount of time that the initial connection attempt network
* operation may block without failing.
* <p>
* The default value for this setting is defined by {@link #DEFAULT_CONNECT_TIMEOUT}
* </p>
*/
int getConnectTimeout();
/**
* Returns the Apache HTTP client instance. This method will not return null.
*
* @see #setHttpClient(HttpClient)
*/
HttpClient getHttpClient();
/**
* Gets the server validation mode for any clients created from this factory. Server
* validation involves the client requesting the server's conformance statement
* to determine whether the server is appropriate for the given client.
* <p>
* The default value for this setting is defined by {@link #DEFAULT_SERVER_VALIDATION_MODE}
* </p>
*/
ServerValidationModeEnum getServerValidationModeEnum();
/**
* Gets the socket timeout, in milliseconds. This is the SO_TIMEOUT time, which is the amount of time that a
* read/write network operation may block without failing.
* <p>
* The default value for this setting is defined by {@link #DEFAULT_SOCKET_TIMEOUT}
* </p>
*/
int getSocketTimeout();
/**
* Instantiates a new client instance
*
@ -40,23 +104,6 @@ public interface IRestfulClientFactory {
*/
<T extends IRestfulClient> T newClient(Class<T> theClientType, String theServerBase);
/**
* Sets the Apache HTTP client instance to be used by any new restful clients created by
* this factory. If set to <code>null</code>, a new HTTP client with
* default settings will be created.
*
* @param theHttpClient An HTTP client instance to use, or <code>null</code>
*/
void setHttpClient(HttpClient theHttpClient);
/**
* Returns the Apache HTTP client instance. This method will not return null.
*
* @see #setHttpClient(HttpClient)
*/
HttpClient getHttpClient();
/**
* Instantiates a new generic client instance
*
@ -67,28 +114,59 @@ public interface IRestfulClientFactory {
IGenericClient newGenericClient(String theServerBase);
/**
* Sets the socket timeout (in milliseconds)
*/
void setSocketTimeout(int theSocketTimeout);
/**
* Sets the connection timeout (in milliseconds)
*/
void setConnectTimeout(int theConnectTimeout);
/**
* Sets the connection request timeout (in milliseconds)
* Sets the connection request timeout, in milliseconds. This is the amount of time that the HTTPClient connection
* pool may wait for an available connection before failing. This setting typically does not need to be adjusted.
* <p>
* The default value for this setting is defined by {@link #DEFAULT_CONNECTION_REQUEST_TIMEOUT}
* </p>
*/
void setConnectionRequestTimeout(int theConnectionRequestTimeout);
/**
* Sets the connect timeout, in milliseconds. This is the amount of time that the initial connection attempt network
* operation may block without failing.
* <p>
* The default value for this setting is defined by {@link #DEFAULT_CONNECT_TIMEOUT}
* </p>
*/
void setConnectTimeout(int theConnectTimeout);
/**
* Sets the Apache HTTP client instance to be used by any new restful clients created by this factory. If set to
* <code>null</code>, a new HTTP client with default settings will be created.
*
* @param theHttpClient
* An HTTP client instance to use, or <code>null</code>
*/
void setHttpClient(HttpClient theHttpClient);
/**
* Sets the HTTP proxy to use for outgoing connections
*
* @param theHost The host (or null to disable proxying, as is the default)
* @param thePort The port (or null to disable proxying, as is the default)
* @param theHost
* The host (or null to disable proxying, as is the default)
* @param thePort
* The port (or null to disable proxying, as is the default)
*/
void setProxy(String theHost, Integer thePort);
/**
* Sets the server validation mode for any clients created from this factory. Server
* validation involves the client requesting the server's conformance statement
* to determine whether the server is appropriate for the given client.
* <p>
* The default value for this setting is defined by {@link #DEFAULT_SERVER_VALIDATION_MODE}
* </p>
*/
void setServerValidationModeEnum(ServerValidationModeEnum theServerValidationMode);
/**
* Sets the socket timeout, in milliseconds. This is the SO_TIMEOUT time, which is the amount of time that a
* read/write network operation may block without failing.
* <p>
* The default value for this setting is defined by {@link #DEFAULT_SOCKET_TIMEOUT}
* </p>
*/
void setSocketTimeout(int theSocketTimeout);
}

View File

@ -24,9 +24,13 @@ import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.http.HttpHost;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
@ -35,26 +39,32 @@ import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.model.base.resource.BaseConformance;
import ca.uhn.fhir.rest.client.api.IRestfulClient;
import ca.uhn.fhir.rest.client.exceptions.FhirClientConnectionException;
import ca.uhn.fhir.rest.method.BaseMethodBinding;
import ca.uhn.fhir.rest.server.Constants;
public class RestfulClientFactory implements IRestfulClientFactory {
private int myConnectionRequestTimeout = 10000;
private int myConnectTimeout = 10000;
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RestfulClientFactory.class);
private int myConnectionRequestTimeout = DEFAULT_CONNECTION_REQUEST_TIMEOUT;
private int myConnectTimeout = DEFAULT_CONNECT_TIMEOUT;
private FhirContext myContext;
private HttpClient myHttpClient;
private Map<Class<? extends IRestfulClient>, ClientInvocationHandlerFactory> myInvocationHandlers = new HashMap<Class<? extends IRestfulClient>, ClientInvocationHandlerFactory>();
private int mySocketTimeout = 10000;
private HttpHost myProxy;
private ServerValidationModeEnum myServerValidationMode = DEFAULT_SERVER_VALIDATION_MODE;
@Override
public void setProxy(String theHost, Integer thePort) {
if (theHost != null) {
myProxy = new HttpHost(theHost, thePort, "http");
} else {
myProxy = null;
}
private int mySocketTimeout = DEFAULT_SOCKET_TIMEOUT;
private Set<String> myValidatedServerBaseUrls = new HashSet<String>();
/**
* Constructor
*/
public RestfulClientFactory() {
}
/**
@ -67,22 +77,6 @@ public class RestfulClientFactory implements IRestfulClientFactory {
myContext = theFhirContext;
}
/**
* Constructor
*/
public RestfulClientFactory() {
}
/**
* Sets the context associated with this client factory. Must not be called more than once.
*/
public void setFhirContext(FhirContext theContext) {
if (myContext != null && myContext != theContext) {
throw new IllegalStateException("RestfulClientFactory instance is already associated with one FhirContext. RestfulClientFactory instances can not be shared.");
}
myContext = theContext;
}
public int getConnectionRequestTimeout() {
return myConnectionRequestTimeout;
}
@ -118,10 +112,22 @@ public class RestfulClientFactory implements IRestfulClientFactory {
return myHttpClient;
}
@Override
public ServerValidationModeEnum getServerValidationModeEnum() {
return myServerValidationMode;
}
@Override
public int getSocketTimeout() {
return mySocketTimeout;
}
@SuppressWarnings("unchecked")
private <T extends IRestfulClient> T instantiateProxy(Class<T> theClientType, InvocationHandler theInvocationHandler) {
T proxy = (T) Proxy.newProxyInstance(theClientType.getClassLoader(), new Class[] { theClientType }, theInvocationHandler);
return proxy;
}
/**
* Instantiates a new client instance
*
@ -139,16 +145,12 @@ public class RestfulClientFactory implements IRestfulClientFactory {
throw new ConfigurationException(theClientType.getCanonicalName() + " is not an interface");
}
HttpClient client = getHttpClient();
String serverBase = theServerBase;
if (!serverBase.endsWith("/")) {
serverBase = serverBase + "/";
}
HttpClient httpClient = getHttpClient();
String serverBase = normalizeAndMaybeValidateServerBase(theServerBase, httpClient);
ClientInvocationHandlerFactory invocationHandler = myInvocationHandlers.get(theClientType);
if (invocationHandler == null) {
invocationHandler = new ClientInvocationHandlerFactory(client, myContext, serverBase, theClientType);
invocationHandler = new ClientInvocationHandlerFactory(httpClient, myContext, serverBase, theClientType);
for (Method nextMethod : theClientType.getMethods()) {
BaseMethodBinding<?> binding = BaseMethodBinding.bindMethod(nextMethod, myContext, null);
invocationHandler.addBinding(nextMethod, binding);
@ -162,8 +164,30 @@ public class RestfulClientFactory implements IRestfulClientFactory {
}
@Override
public IGenericClient newGenericClient(String theServerBase) {
return new GenericClient(myContext, getHttpClient(), theServerBase);
public synchronized IGenericClient newGenericClient(String theServerBase) {
HttpClient httpClient = getHttpClient();
String serverBase = normalizeAndMaybeValidateServerBase(theServerBase, httpClient);
return new GenericClient(myContext, httpClient, serverBase);
}
private String normalizeAndMaybeValidateServerBase(String theServerBase, HttpClient theHttpClient) {
String serverBase = theServerBase;
if (!serverBase.endsWith("/")) {
serverBase = serverBase + "/";
}
switch (myServerValidationMode) {
case NEVER:
break;
case ONCE:
if (!myValidatedServerBaseUrls.contains(serverBase)) {
validateServerBase(serverBase, theHttpClient);
myValidatedServerBaseUrls.add(serverBase);
}
break;
}
return serverBase;
}
@Override
@ -178,6 +202,16 @@ public class RestfulClientFactory implements IRestfulClientFactory {
myHttpClient = null;
}
/**
* Sets the context associated with this client factory. Must not be called more than once.
*/
public void setFhirContext(FhirContext theContext) {
if (myContext != null && myContext != theContext) {
throw new IllegalStateException("RestfulClientFactory instance is already associated with one FhirContext. RestfulClientFactory instances can not be shared.");
}
myContext = theContext;
}
/**
* Sets the Apache HTTP client instance to be used by any new restful clients created by this factory. If set to
* <code>null</code>, which is the default, a new HTTP client with default settings will be created.
@ -190,16 +224,58 @@ public class RestfulClientFactory implements IRestfulClientFactory {
myHttpClient = theHttpClient;
}
@Override
public void setProxy(String theHost, Integer thePort) {
if (theHost != null) {
myProxy = new HttpHost(theHost, thePort, "http");
} else {
myProxy = null;
}
}
@Override
public void setServerValidationModeEnum(ServerValidationModeEnum theServerValidationMode) {
Validate.notNull(theServerValidationMode, "theServerValidationMode may not be null");
myServerValidationMode = theServerValidationMode;
}
@Override
public synchronized void setSocketTimeout(int theSocketTimeout) {
mySocketTimeout = theSocketTimeout;
myHttpClient = null;
}
@SuppressWarnings("unchecked")
private <T extends IRestfulClient> T instantiateProxy(Class<T> theClientType, InvocationHandler theInvocationHandler) {
T proxy = (T) Proxy.newProxyInstance(theClientType.getClassLoader(), new Class[] { theClientType }, theInvocationHandler);
return proxy;
private void validateServerBase(String theServerBase, HttpClient theHttpClient) {
GenericClient client = new GenericClient(myContext, theHttpClient, theServerBase);
BaseConformance conformance;
try {
conformance = client.conformance();
} catch (FhirClientConnectionException e) {
throw new FhirClientConnectionException(myContext.getLocalizer().getMessage(RestfulClientFactory.class, "failedToRetrieveConformance", theServerBase + Constants.URL_TOKEN_METADATA), e);
}
String serverFhirVersionString = conformance.getFhirVersionElement().getValueAsString();
FhirVersionEnum serverFhirVersionEnum = null;
if (StringUtils.isBlank(serverFhirVersionString)) {
// we'll be lenient and accept this
} else {
if (serverFhirVersionString.startsWith("0.80") || serverFhirVersionString.startsWith("0.0.8")) {
serverFhirVersionEnum = FhirVersionEnum.DSTU1;
} else if (serverFhirVersionString.startsWith("0.4")) {
serverFhirVersionEnum = FhirVersionEnum.DSTU2;
} else {
// we'll be lenient and accept this
ourLog.debug("Server conformance statement indicates unknown FHIR version: {}", serverFhirVersionString);
}
}
if (serverFhirVersionEnum != null) {
FhirVersionEnum contextFhirVersion = myContext.getVersion().getVersion();
if (!contextFhirVersion.isEquivalentTo(serverFhirVersionEnum)) {
throw new FhirClientConnectionException(myContext.getLocalizer().getMessage(RestfulClientFactory.class, "wrongVersionInConformance", theServerBase + Constants.URL_TOKEN_METADATA, serverFhirVersionString, serverFhirVersionEnum, contextFhirVersion));
}
}
}
}

View File

@ -0,0 +1,19 @@
package ca.uhn.fhir.rest.client;
import ca.uhn.fhir.context.FhirContext;
public enum ServerValidationModeEnum {
/**
* Do not validate the server's conformance statement before attempting to
* call it.
*/
NEVER,
/**
* Validate the server's conformance statement once (per base URL) and cache the
* results for the lifetime of the {@link FhirContext}
*/
ONCE
}

View File

@ -22,13 +22,24 @@ package ca.uhn.fhir.rest.client.exceptions;
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
/**
* Represents a failure by the HAPI FHIR Client to successfully communicate
* with a FHIR server, because of IO failures, incomprehensible response, etc.
*/
public class FhirClientConnectionException extends BaseServerResponseException {
private static final long serialVersionUID = 1L;
public FhirClientConnectionException(Throwable theE) {
super(0, theE);
public FhirClientConnectionException(Throwable theCause) {
super(0, theCause);
}
public FhirClientConnectionException(String theMessage, Throwable theCause) {
super(0, theMessage, theCause);
}
public FhirClientConnectionException(String theMessage) {
super(0, theMessage);
}
}

View File

@ -79,7 +79,7 @@ public class HttpGetClientInvocation extends BaseHttpClientInvocation {
}
@Override
public HttpRequestBase asHttpRequest(String theUrlBase, Map<String, List<String>> theExtraParams, EncodingEnum theEncoding) {
public HttpGet asHttpRequest(String theUrlBase, Map<String, List<String>> theExtraParams, EncodingEnum theEncoding) {
StringBuilder b = new StringBuilder();
if (!myUrlPath.contains("://")) {

View File

@ -109,6 +109,7 @@ public class Constants {
public static final int STATUS_HTTP_500_INTERNAL_ERROR = 500;
public static final int STATUS_HTTP_501_NOT_IMPLEMENTED = 501;
public static final String URL_TOKEN_HISTORY = "_history";
public static final String URL_TOKEN_METADATA = "metadata";
static {
Map<String, EncodingEnum> valToEncoding = new HashMap<String, EncodingEnum>();

View File

@ -502,7 +502,7 @@ public class RestfulServer extends HttpServlet {
ResourceBinding resourceBinding = null;
BaseMethodBinding<?> resourceMethod = null;
if ("metadata".equals(resourceName) || theRequestType == RequestType.OPTIONS) {
if (Constants.URL_TOKEN_METADATA.equals(resourceName) || theRequestType == RequestType.OPTIONS) {
resourceMethod = myServerConformanceMethod;
} else if (resourceName == null) {
resourceBinding = myNullResourceBinding;

View File

@ -24,6 +24,10 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
/**
* Used internally by HAPI to log the version of the HAPI FHIR framework
* once, when the framework is first loaded by the classloader.
*/
public class VersionUtil {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(VersionUtil.class);
@ -32,7 +36,7 @@ public class VersionUtil {
static {
initialize();
}
public static String getVersion() {
return ourVersion;
}
@ -40,12 +44,11 @@ public class VersionUtil {
private static void initialize() {
InputStream is = null;
try {
is = VersionUtil.class
.getResourceAsStream("/ca/uhn/fhir/hapi-version.properties");
is = VersionUtil.class.getResourceAsStream("/ca/uhn/fhir/hapi-version.properties");
Properties p = new Properties();
p.load(is);
ourVersion = p.getProperty("version");
ourLog.info("HAPI-FHIR version is: " + ourVersion);
ourLog.info("HAPI FHIR version is: " + ourVersion);
} catch (IOException e) {
ourLog.warn("Unable to determine HAPI version information", e);
} finally {

View File

@ -7,6 +7,8 @@ ca.uhn.fhir.context.RuntimeResourceDefinition.nonInstantiableType=Resource type
ca.uhn.fhir.rest.client.GenericClient.noVersionIdForVread=No version specified in URL for 'vread' operation: {0}
ca.uhn.fhir.rest.client.GenericClient.incompleteUriForRead=The given URI is not an absolute URL and is not usable for this operation: {0}
ca.uhn.fhir.rest.client.GenericClient.cannotDetermineResourceTypeFromUri=Unable to determine the resource type from the given URI: {0}
ca.uhn.fhir.rest.client.RestfulClientFactory.failedToRetrieveConformance=Failed to retrieve the server's metadata statement during client initialization. URL used was: {0}
ca.uhn.fhir.rest.client.RestfulClientFactory.wrongVersionInConformance=The server at base URL "{0}" returned a conformance statement indicating that it supports FHIR version "{1}" which corresponds to {2}, but this client is configured to use {3} (via the FhirContext).
ca.uhn.fhir.rest.method.IncludeParameter.invalidIncludeNameInRequest=Invalid _include parameter value: '{0}'. Valid values are: {1}
ca.uhn.fhir.rest.method.IncludeParameter.orIncludeInRequest='OR' query parameters (values containing ',') are not supported in _include parameters

View File

@ -0,0 +1,86 @@
package ca.uhn.fhir.rest.client;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import java.io.StringReader;
import java.nio.charset.Charset;
import org.apache.commons.io.input.ReaderInputStream;
import org.apache.http.HttpResponse;
import org.apache.http.ProtocolVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicStatusLine;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Matchers;
import org.mockito.internal.stubbing.defaultanswers.ReturnsDeepStubs;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.dev.resource.Conformance;
import ca.uhn.fhir.rest.client.exceptions.FhirClientConnectionException;
import ca.uhn.fhir.rest.server.Constants;
public class ClientServerValidationTestDstu1 {
private FhirContext myCtx;
private HttpClient myHttpClient;
private HttpResponse myHttpResponse;
@Before
public void before() {
myHttpClient = mock(HttpClient.class, new ReturnsDeepStubs());
myHttpResponse = mock(HttpResponse.class, new ReturnsDeepStubs());
myCtx = FhirContext.forDstu1();
myCtx.getRestfulClientFactory().setHttpClient(myHttpClient);
}
@Test
public void testServerReturnsAppropriateVersion() throws Exception {
Conformance conf = new Conformance();
conf.setFhirVersion("0.4.0");
String msg = myCtx.newXmlParser().encodeResourceToString(conf);
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
myCtx.getRestfulClientFactory().setServerValidationModeEnum(ServerValidationModeEnum.ONCE);
myCtx.newRestfulGenericClient("http://foo");
myCtx.newRestfulGenericClient("http://foo");
verify(myHttpClient, times(1)).execute(Matchers.any(HttpUriRequest.class));
}
@Test
public void testServerReturnsWrongVersion() throws Exception {
Conformance conf = new Conformance();
conf.setFhirVersion("0.8.0");
String msg = myCtx.newXmlParser().encodeResourceToString(conf);
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
myCtx.getRestfulClientFactory().setServerValidationModeEnum(ServerValidationModeEnum.ONCE);
try {
myCtx.newRestfulGenericClient("http://foo");
fail();
} catch (FhirClientConnectionException e) {
assertThat(e.toString(), containsString("The server at base URL \"http://foo/metadata\" returned a conformance statement indicating that it supports FHIR version \"0.4\" which corresponds to DSTU2, but this client is configured to use DSTU1 (at FhirContext creation time)"));
}
}
}

View File

@ -39,6 +39,7 @@ public class BasicAuthInterceptorTest {
public void before() {
myHttpClient = mock(HttpClient.class, new ReturnsDeepStubs());
ourCtx.getRestfulClientFactory().setHttpClient(myHttpClient);
ourCtx.getRestfulClientFactory().setServerValidationModeEnum(ServerValidationModeEnum.NEVER);
myHttpResponse = mock(HttpResponse.class, new ReturnsDeepStubs());
}

View File

@ -39,6 +39,7 @@ public class BearerTokenAuthInterceptorTest {
public void before() {
myHttpClient = mock(HttpClient.class, new ReturnsDeepStubs());
ourCtx.getRestfulClientFactory().setHttpClient(myHttpClient);
ourCtx.getRestfulClientFactory().setServerValidationModeEnum(ServerValidationModeEnum.NEVER);
myHttpResponse = mock(HttpResponse.class, new ReturnsDeepStubs());
}

View File

@ -47,6 +47,7 @@ public class BinaryClientTest {
httpClient = mock(HttpClient.class, new ReturnsDeepStubs());
ctx.getRestfulClientFactory().setHttpClient(httpClient);
ctx.getRestfulClientFactory().setServerValidationModeEnum(ServerValidationModeEnum.NEVER);
httpResponse = mock(HttpResponse.class, new ReturnsDeepStubs());
}

View File

@ -51,6 +51,7 @@ public class ClientIntegrationTest {
}
@SuppressWarnings("deprecation")
@Test
public void testClientSecurity() throws Exception {

View File

@ -0,0 +1,86 @@
package ca.uhn.fhir.rest.client;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import java.io.StringReader;
import java.nio.charset.Charset;
import org.apache.commons.io.input.ReaderInputStream;
import org.apache.http.HttpResponse;
import org.apache.http.ProtocolVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicStatusLine;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Matchers;
import org.mockito.internal.stubbing.defaultanswers.ReturnsDeepStubs;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.dstu.resource.Conformance;
import ca.uhn.fhir.rest.client.exceptions.FhirClientConnectionException;
import ca.uhn.fhir.rest.server.Constants;
public class ClientServerValidationTest {
private FhirContext myCtx;
private HttpClient myHttpClient;
private HttpResponse myHttpResponse;
@Before
public void before() {
myHttpClient = mock(HttpClient.class, new ReturnsDeepStubs());
myHttpResponse = mock(HttpResponse.class, new ReturnsDeepStubs());
myCtx = FhirContext.forDev();
myCtx.getRestfulClientFactory().setHttpClient(myHttpClient);
}
@Test
public void testServerReturnsAppropriateVersionDev() throws Exception {
Conformance conf = new Conformance();
conf.setFhirVersion("0.4.0");
String msg = myCtx.newXmlParser().encodeResourceToString(conf);
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
myCtx.getRestfulClientFactory().setServerValidationModeEnum(ServerValidationModeEnum.ONCE);
myCtx.newRestfulGenericClient("http://foo");
myCtx.newRestfulGenericClient("http://foo");
verify(myHttpClient, times(1)).execute(Matchers.any(HttpUriRequest.class));
}
@Test
public void testServerReturnsWrongVersionDev() throws Exception {
Conformance conf = new Conformance();
conf.setFhirVersion("0.0.8");
String msg = myCtx.newXmlParser().encodeResourceToString(conf);
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
myCtx.getRestfulClientFactory().setServerValidationModeEnum(ServerValidationModeEnum.ONCE);
try {
myCtx.newRestfulGenericClient("http://foo");
fail();
} catch (FhirClientConnectionException e) {
assertThat(e.toString(), containsString("The server at base URL \"http://foo/metadata\" returned a conformance statement indicating that it supports FHIR version \"0.4\" which corresponds to DSTU2, but this client is configured to use DSTU1 (at FhirContext creation time)"));
}
}
}

View File

@ -88,6 +88,7 @@ public class ClientTest {
httpClient = mock(HttpClient.class, new ReturnsDeepStubs());
ctx.getRestfulClientFactory().setHttpClient(httpClient);
ctx.getRestfulClientFactory().setServerValidationModeEnum(ServerValidationModeEnum.NEVER);
httpResponse = mock(HttpResponse.class, new ReturnsDeepStubs());
}

View File

@ -32,20 +32,21 @@ import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
public class ExceptionHandlingTest {
private static FhirContext myCtx;
private static FhirContext ourCtx;
private HttpClient myHttpClient;
private HttpResponse myHttpResponse;
@BeforeClass
public static void beforeClass() {
myCtx = new FhirContext();
ourCtx = new FhirContext();
}
@Before
public void before() {
myHttpClient = mock(HttpClient.class, new ReturnsDeepStubs());
myCtx.getRestfulClientFactory().setHttpClient(myHttpClient);
ourCtx.getRestfulClientFactory().setHttpClient(myHttpClient);
ourCtx.getRestfulClientFactory().setServerValidationModeEnum(ServerValidationModeEnum.NEVER);
myHttpResponse = mock(HttpResponse.class, new ReturnsDeepStubs());
}
@ -61,7 +62,7 @@ public class ExceptionHandlingTest {
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", contentType + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
try {
client.read(Patient.class, new IdDt("Patient/1234"));
@ -77,7 +78,7 @@ public class ExceptionHandlingTest {
public void testFail500WithOperationOutcomeMessage() throws Exception {
OperationOutcome oo = new OperationOutcome();
oo.getIssueFirstRep().getDetails().setValue("Help I'm a bug");
String msg = myCtx.newXmlParser().encodeResourceToString(oo);
String msg = ourCtx.newXmlParser().encodeResourceToString(oo);
String contentType = Constants.CT_FHIR_XML;
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
@ -86,7 +87,7 @@ public class ExceptionHandlingTest {
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", contentType + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
try {
client.read(Patient.class, new IdDt("Patient/1234"));
@ -102,7 +103,7 @@ public class ExceptionHandlingTest {
public void testFail500WithUnexpectedResource() throws Exception {
Patient patient = new Patient();
patient.addIdentifier().setSystem("foo").setValue("bar");
String msg = myCtx.newXmlParser().encodeResourceToString(patient);
String msg = ourCtx.newXmlParser().encodeResourceToString(patient);
String contentType = Constants.CT_FHIR_XML;
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
@ -111,7 +112,7 @@ public class ExceptionHandlingTest {
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", contentType + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
try {
client.read(Patient.class, new IdDt("Patient/1234"));
@ -128,7 +129,7 @@ public class ExceptionHandlingTest {
public void testFail500WithOperationOutcomeMessageJson() throws Exception {
OperationOutcome oo = new OperationOutcome();
oo.getIssueFirstRep().getDetails().setValue("Help I'm a bug");
String msg = myCtx.newJsonParser().encodeResourceToString(oo);
String msg = ourCtx.newJsonParser().encodeResourceToString(oo);
String contentType = Constants.CT_FHIR_JSON;
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
@ -137,7 +138,7 @@ public class ExceptionHandlingTest {
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", contentType + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
try {
client.read(Patient.class, new IdDt("Patient/1234"));
fail();
@ -154,7 +155,7 @@ public class ExceptionHandlingTest {
public void testFail500WithOperationOutcomeMessageGeneric() throws Exception {
OperationOutcome oo = new OperationOutcome();
oo.getIssueFirstRep().getDetails().setValue("Help I'm a bug");
String msg = myCtx.newJsonParser().encodeResourceToString(oo);
String msg = ourCtx.newJsonParser().encodeResourceToString(oo);
String contentType = Constants.CT_FHIR_JSON;
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
@ -163,7 +164,7 @@ public class ExceptionHandlingTest {
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", contentType + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
IMyClient client = myCtx.newRestfulClient(IMyClient.class,"http://example.com/fhir");
IMyClient client = ourCtx.newRestfulClient(IMyClient.class,"http://example.com/fhir");
try {
client.read(new IdDt("Patient/1234"));
fail();

View File

@ -24,7 +24,6 @@ import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicStatusLine;
import org.apache.http.util.EncodingUtils;
import org.hamcrest.core.StringContains;
import org.junit.Before;
import org.junit.BeforeClass;
@ -55,7 +54,7 @@ import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
public class GenericClientTest {
private static FhirContext myCtx;
private static FhirContext ourCtx;
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(GenericClientTest.class);
private HttpClient myHttpClient;
@ -65,7 +64,8 @@ public class GenericClientTest {
public void before() {
myHttpClient = mock(HttpClient.class, new ReturnsDeepStubs());
myCtx.getRestfulClientFactory().setHttpClient(myHttpClient);
ourCtx.getRestfulClientFactory().setHttpClient(myHttpClient);
ourCtx.getRestfulClientFactory().setServerValidationModeEnum(ServerValidationModeEnum.NEVER);
myHttpResponse = mock(HttpResponse.class, new ReturnsDeepStubs());
}
@ -133,16 +133,16 @@ public class GenericClientTest {
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8")));
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
int count = 0;
client.create().resource(myCtx.newXmlParser().encodeResourceToString(p1)).execute();
client.create().resource(ourCtx.newXmlParser().encodeResourceToString(p1)).execute();
assertEquals(1, capt.getAllValues().get(count).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(count).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertThat(extractBody(capt, count), containsString("value=\"John\""));
count++;
client.create().resource(myCtx.newJsonParser().encodeResourceToString(p1)).execute();
client.create().resource(ourCtx.newJsonParser().encodeResourceToString(p1)).execute();
assertEquals(1, capt.getAllValues().get(count).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.JSON.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(count).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertThat(extractBody(capt, count), containsString("[\"John\"]"));
@ -152,13 +152,13 @@ public class GenericClientTest {
* e.g. Now try with reversed encoding (provide a string that's in JSON and ask the client to use XML)
*/
client.create().resource(myCtx.newXmlParser().encodeResourceToString(p1)).encodedJson().execute();
client.create().resource(ourCtx.newXmlParser().encodeResourceToString(p1)).encodedJson().execute();
assertEquals(1, capt.getAllValues().get(count).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.JSON.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(count).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertThat(extractBody(capt, count), containsString("[\"John\"]"));
count++;
client.create().resource(myCtx.newJsonParser().encodeResourceToString(p1)).encodedXml().execute();
client.create().resource(ourCtx.newJsonParser().encodeResourceToString(p1)).encodedXml().execute();
assertEquals(1, capt.getAllValues().get(count).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(count).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertThat(extractBody(capt, count), containsString("value=\"John\""));
@ -183,7 +183,7 @@ public class GenericClientTest {
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8")));
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
MethodOutcome outcome = client.create().resource(p1).execute();
assertEquals("44", outcome.getId().getIdPart());
@ -237,7 +237,7 @@ public class GenericClientTest {
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8")));
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
MethodOutcome outcome = client.create(p1);
assertEquals("44", outcome.getId().getIdPart());
@ -267,7 +267,7 @@ public class GenericClientTest {
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8")));
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
int count = 0;
client.create().resource(org).prettyPrint().encodedXml().execute();
@ -282,7 +282,7 @@ public class GenericClientTest {
public void testDelete() throws Exception {
OperationOutcome oo = new OperationOutcome();
oo.addIssue().addLocation().setValue("testDelete01");
String ooStr = myCtx.newXmlParser().encodeResourceToString(oo);
String ooStr = ourCtx.newXmlParser().encodeResourceToString(oo);
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
@ -291,7 +291,7 @@ public class GenericClientTest {
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(ooStr), Charset.forName("UTF-8")));
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
OperationOutcome outcome = (OperationOutcome) client.delete().resourceById("Patient", "123").execute();
@ -313,7 +313,7 @@ public class GenericClientTest {
TagList tagList = new TagList();
tagList.add(new Tag("CCC", "AAA", "BBB"));
String msg = myCtx.newXmlParser().encodeTagListToString(tagList);
String msg = ourCtx.newXmlParser().encodeTagListToString(tagList);
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
@ -321,7 +321,7 @@ public class GenericClientTest {
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
//@formatter:off
TagList response = client.getTags()
@ -361,7 +361,7 @@ public class GenericClientTest {
new BasicHeader(Constants.HEADER_CATEGORY, "http://foo/tagdefinition.html; scheme=\"http://hl7.org/fhir/tag\"; label=\"Some tag\"") };
when(myHttpResponse.getAllHeaders()).thenReturn(headers);
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
//@formatter:off
Patient response = client.read(Patient.class, new IdDt("Patient/1234"));
@ -399,7 +399,7 @@ public class GenericClientTest {
new BasicHeader(Constants.HEADER_CATEGORY, "http://foo/tagdefinition.html; scheme=\"http://hl7.org/fhir/tag\"; label=\"Some tag\"") };
when(myHttpResponse.getAllHeaders()).thenReturn(headers);
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
int count = 0;
@ -440,7 +440,7 @@ public class GenericClientTest {
new BasicHeader(Constants.HEADER_CATEGORY, "http://foo/tagdefinition.html; scheme=\"http://hl7.org/fhir/tag\"; label=\"Some tag\"") };
when(myHttpResponse.getAllHeaders()).thenReturn(headers);
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
Patient response = client.read(Patient.class, new IdDt("http://somebase.com/path/to/base/Patient/1234"));
assertThat(response.getNameFirstRep().getFamilyAsSingleString(), StringContains.containsString("Cardinal"));
@ -465,7 +465,7 @@ public class GenericClientTest {
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
//@formatter:off
Bundle response = client.search()
@ -490,7 +490,7 @@ public class GenericClientTest {
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
String longValue = StringUtils.leftPad("", 20000, 'B');
@ -523,7 +523,7 @@ public class GenericClientTest {
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
IGenericClient client = myCtx.newRestfulGenericClient("http://foo");
IGenericClient client = ourCtx.newRestfulGenericClient("http://foo");
//@formatter:off
Bundle response = client
.search()
@ -564,7 +564,7 @@ public class GenericClientTest {
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
IGenericClient client = myCtx.newRestfulGenericClient("http://foo");
IGenericClient client = ourCtx.newRestfulGenericClient("http://foo");
//@formatter:off
Bundle response = client.search()
@ -592,7 +592,7 @@ public class GenericClientTest {
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
//@formatter:off
Bundle response = client.search()
@ -625,7 +625,7 @@ public class GenericClientTest {
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
//@formatter:off
Bundle response = client.search()
@ -650,7 +650,7 @@ public class GenericClientTest {
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
//@formatter:off
Bundle response = client.search()
@ -676,7 +676,7 @@ public class GenericClientTest {
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
//@formatter:off
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
Bundle response = client.search()
.forResource(Patient.class)
@ -700,7 +700,7 @@ public class GenericClientTest {
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
//@formatter:off
Bundle response = client.search()
@ -725,7 +725,7 @@ public class GenericClientTest {
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
//@formatter:off
Bundle response = client.search()
@ -760,7 +760,7 @@ public class GenericClientTest {
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
//@formatter:off
Bundle response = client.search()
@ -785,7 +785,7 @@ public class GenericClientTest {
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
//@formatter:off
Bundle response = client.search()
@ -830,7 +830,7 @@ public class GenericClientTest {
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
//@formatter:off
Bundle response = client.search()
@ -855,7 +855,7 @@ public class GenericClientTest {
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
//@formatter:off
Bundle response = client.search()
@ -885,7 +885,7 @@ public class GenericClientTest {
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
Bundle response = client
.search(new UriDt(
@ -909,7 +909,7 @@ public class GenericClientTest {
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
Bundle response = client
.search(Patient.class,
@ -935,7 +935,7 @@ public class GenericClientTest {
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
GenericClient client = (GenericClient) myCtx.newRestfulGenericClient("http://example.com/fhir");
GenericClient client = (GenericClient) ourCtx.newRestfulGenericClient("http://example.com/fhir");
client.setPrettyPrint(true);
client.setEncoding(EncodingEnum.JSON);
@ -961,7 +961,7 @@ public class GenericClientTest {
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_TEXT + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader("Server Issues!"), Charset.forName("UTF-8")));
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
try {
client.search().forResource(Patient.class).execute();
@ -985,7 +985,7 @@ public class GenericClientTest {
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_TEXT + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader("Server Issues!"), Charset.forName("UTF-8")));
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
try {
client.search().forResource(Patient.class).execute();
@ -999,7 +999,7 @@ public class GenericClientTest {
@Test
public void testTransaction() throws Exception {
String bundleStr = IOUtils.toString(getClass().getResourceAsStream("/bundle.json"));
Bundle bundle = myCtx.newJsonParser().parseBundle(bundleStr);
Bundle bundle = ourCtx.newJsonParser().parseBundle(bundleStr);
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
@ -1007,7 +1007,7 @@ public class GenericClientTest {
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_JSON + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(bundleStr), Charset.forName("UTF-8")));
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
//@formatter:off
Bundle response = client.transaction()
@ -1024,7 +1024,7 @@ public class GenericClientTest {
@Test
public void testTransactionJson() throws Exception {
String bundleStr = IOUtils.toString(getClass().getResourceAsStream("/bundle.json"));
Bundle bundle = myCtx.newJsonParser().parseBundle(bundleStr);
Bundle bundle = ourCtx.newJsonParser().parseBundle(bundleStr);
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
@ -1032,7 +1032,7 @@ public class GenericClientTest {
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_JSON + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(bundleStr), Charset.forName("UTF-8")));
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
//@formatter:off
Bundle response = client.transaction()
@ -1069,7 +1069,7 @@ public class GenericClientTest {
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8")));
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
try {
client.update().resource(p1).execute();
@ -1135,16 +1135,16 @@ public class GenericClientTest {
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8")));
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
int count = 0;
client.update().resource(myCtx.newXmlParser().encodeResourceToString(p1)).withId("1").execute();
client.update().resource(ourCtx.newXmlParser().encodeResourceToString(p1)).withId("1").execute();
assertEquals(1, capt.getAllValues().get(count).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(count).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertThat(extractBody(capt, count), containsString("value=\"John\""));
count++;
client.update().resource(myCtx.newJsonParser().encodeResourceToString(p1)).withId("1").execute();
client.update().resource(ourCtx.newJsonParser().encodeResourceToString(p1)).withId("1").execute();
assertEquals(1, capt.getAllValues().get(count).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.JSON.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(count).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertThat(extractBody(capt, count), containsString("[\"John\"]"));
@ -1154,13 +1154,13 @@ public class GenericClientTest {
* e.g. Now try with reversed encoding (provide a string that's in JSON and ask the client to use XML)
*/
client.update().resource(myCtx.newXmlParser().encodeResourceToString(p1)).withId("1").encodedJson().execute();
client.update().resource(ourCtx.newXmlParser().encodeResourceToString(p1)).withId("1").encodedJson().execute();
assertEquals(1, capt.getAllValues().get(count).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.JSON.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(count).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertThat(extractBody(capt, count), containsString("[\"John\"]"));
count++;
client.update().resource(myCtx.newJsonParser().encodeResourceToString(p1)).withId("1").encodedXml().execute();
client.update().resource(ourCtx.newJsonParser().encodeResourceToString(p1)).withId("1").encodedXml().execute();
assertEquals(1, capt.getAllValues().get(count).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(count).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertThat(extractBody(capt, count), containsString("value=\"John\""));
@ -1182,7 +1182,7 @@ public class GenericClientTest {
new BasicHeader(Constants.HEADER_CATEGORY, "http://foo/tagdefinition.html; scheme=\"http://hl7.org/fhir/tag\"; label=\"Some tag\"") };
when(myHttpResponse.getAllHeaders()).thenReturn(headers);
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
Patient response = client.vread(Patient.class, new IdDt("http://somebase.com/path/to/base/Patient/1234/_history/2222"));
assertThat(response.getNameFirstRep().getFamilyAsSingleString(), StringContains.containsString("Cardinal"));
@ -1199,7 +1199,7 @@ public class GenericClientTest {
@BeforeClass
public static void beforeClass() {
myCtx = new FhirContext();
ourCtx = new FhirContext();
}
}

View File

@ -45,6 +45,7 @@ public class IncludedResourceStitchingClientTest {
httpClient = mock(HttpClient.class, new ReturnsDeepStubs());
ctx.getRestfulClientFactory().setHttpClient(httpClient);
ctx.getRestfulClientFactory().setServerValidationModeEnum(ServerValidationModeEnum.NEVER);
httpResponse = mock(HttpResponse.class, new ReturnsDeepStubs());
}

View File

@ -96,6 +96,8 @@ public class LoggingInterceptorTest {
proxyHandler.addServletWithMapping(servletHolder, "/*");
ourServer.setHandler(proxyHandler);
ourServer.start();
ourCtx.getRestfulClientFactory().setServerValidationModeEnum(ServerValidationModeEnum.NEVER);
}
/**

View File

@ -44,6 +44,7 @@ public class ReferenceClientTest {
httpClient = mock(HttpClient.class, new ReturnsDeepStubs());
ctx.getRestfulClientFactory().setHttpClient(httpClient);
ctx.getRestfulClientFactory().setServerValidationModeEnum(ServerValidationModeEnum.NEVER);
httpResponse = mock(HttpResponse.class, new ReturnsDeepStubs());
}

View File

@ -54,6 +54,7 @@ public class SearchTest {
httpClient = mock(HttpClient.class, new ReturnsDeepStubs());
ctx.getRestfulClientFactory().setHttpClient(httpClient);
ctx.getRestfulClientFactory().setServerValidationModeEnum(ServerValidationModeEnum.NEVER);
httpResponse = mock(HttpResponse.class, new ReturnsDeepStubs());
}

View File

@ -47,6 +47,7 @@ public class SortClientTest {
httpClient = mock(HttpClient.class, new ReturnsDeepStubs());
ctx.getRestfulClientFactory().setHttpClient(httpClient);
ctx.getRestfulClientFactory().setServerValidationModeEnum(ServerValidationModeEnum.NEVER);
httpResponse = mock(HttpResponse.class, new ReturnsDeepStubs());
}

View File

@ -44,6 +44,7 @@ public class StringClientTest {
httpClient = mock(HttpClient.class, new ReturnsDeepStubs());
ctx.getRestfulClientFactory().setHttpClient(httpClient);
ctx.getRestfulClientFactory().setServerValidationModeEnum(ServerValidationModeEnum.NEVER);
httpResponse = mock(HttpResponse.class, new ReturnsDeepStubs());
}

View File

@ -51,6 +51,7 @@ public class TagsClientTest {
httpClient = mock(HttpClient.class, new ReturnsDeepStubs());
ctx.getRestfulClientFactory().setHttpClient(httpClient);
ctx.getRestfulClientFactory().setServerValidationModeEnum(ServerValidationModeEnum.NEVER);
httpResponse = mock(HttpResponse.class, new ReturnsDeepStubs());
}

View File

@ -49,7 +49,8 @@ public class TransactionClientTest {
httpClient = mock(HttpClient.class, new ReturnsDeepStubs());
ctx.getRestfulClientFactory().setHttpClient(httpClient);
ctx.getRestfulClientFactory().setServerValidationModeEnum(ServerValidationModeEnum.NEVER);
httpResponse = mock(HttpResponse.class, new ReturnsDeepStubs());
}

View File

@ -76,13 +76,20 @@
may cause issues if other applications have been coded to depend on the
incorrect behaviour. Thanks to Mochaholic for reporting!
</action>
</release>
<action type="fix" issue="91" due-to="andyhuang91">
Custom/user defined resource definitions which contained more than one
child with no order defined failed to initialize properly. Thanks to
Andy Huang for reporting and figuring out where the
problem was!
</action>
<action type="add">
RESTful Client now queries the server (only once per server base URL) to ensure that
the given server corresponds to the correct version of the FHIR specification, as
defined by the FhirContext. This behaviour can be disabled by setting the
appropriate configuration on the
RestfulClientConfig. Thanks to Grahame Grieve for the suggestion!
</action>
</release>
<release version="0.8" date="2014-Dec-17">
<action type="add">
<![CDATA[<b>API CHANGE:</b>]]> The "FHIR structures" for DSTU1 (the classes which model the