Allow client defined parameter style for _format param

This commit is contained in:
James Agnew 2018-11-08 15:27:35 -05:00
parent 3ae5f9a3b7
commit 82ec721c99
5 changed files with 241 additions and 177 deletions

View File

@ -0,0 +1,14 @@
package ca.uhn.fhir.rest.api;
public enum RequestFormatParamStyleEnum {
/**
* Do not include a _format parameter on requests
*/
NONE,
/**
* "xml" or "json"
*/
SHORT
}

View File

@ -1,5 +1,11 @@
package ca.uhn.fhir.rest.client.api; package ca.uhn.fhir.rest.client.api;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.api.RequestFormatParamStyleEnum;
import ca.uhn.fhir.rest.api.SummaryEnum;
import org.hl7.fhir.instance.model.api.IBaseResource;
import java.util.List; import java.util.List;
/* /*
@ -22,12 +28,6 @@ import java.util.List;
* #L% * #L%
*/ */
import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.api.SummaryEnum;
public interface IRestfulClient { public interface IRestfulClient {
/** /**
@ -35,10 +35,8 @@ public interface IRestfulClient {
* method could be used as a low level implementation of a read/vread/search * method could be used as a low level implementation of a read/vread/search
* operation. * operation.
* *
* @param theResourceType * @param theResourceType The resource type to parse
* The resource type to parse * @param theUrl The URL to load
* @param theUrl
* The URL to load
* @return The parsed resource * @return The parsed resource
*/ */
<T extends IBaseResource> T fetchResourceFromUrl(Class<T> theResourceType, String theUrl); <T extends IBaseResource> T fetchResourceFromUrl(Class<T> theResourceType, String theUrl);
@ -49,6 +47,17 @@ public interface IRestfulClient {
*/ */
EncodingEnum getEncoding(); EncodingEnum getEncoding();
/**
* Specifies that the client should use the given encoding to do its
* queries. This means that the client will append the "_format" param
* to GET methods (read/search/etc), and will add an appropriate header for
* write methods.
*
* @param theEncoding The encoding to use in the request, or <code>null</code> not specify
* an encoding (which generally implies the use of XML). The default is <code>null</code>.
*/
void setEncoding(EncodingEnum theEncoding);
/** /**
* Returns the FHIR context associated with this client * Returns the FHIR context associated with this client
*/ */
@ -76,25 +85,12 @@ public interface IRestfulClient {
*/ */
void registerInterceptor(IClientInterceptor theInterceptor); void registerInterceptor(IClientInterceptor theInterceptor);
/**
* Specifies that the client should use the given encoding to do its
* queries. This means that the client will append the "_format" param
* to GET methods (read/search/etc), and will add an appropriate header for
* write methods.
*
* @param theEncoding
* The encoding to use in the request, or <code>null</code> not specify
* an encoding (which generally implies the use of XML). The default is <code>null</code>.
*/
void setEncoding(EncodingEnum theEncoding);
/** /**
* Specifies that the client should request that the server respond with "pretty printing" * Specifies that the client should request that the server respond with "pretty printing"
* enabled. Note that this is a non-standard parameter, not all servers will * enabled. Note that this is a non-standard parameter, not all servers will
* support it. * support it.
* *
* @param thePrettyPrint * @param thePrettyPrint The pretty print flag to use in the request (default is <code>false</code>)
* The pretty print flag to use in the request (default is <code>false</code>)
*/ */
void setPrettyPrint(Boolean thePrettyPrint); void setPrettyPrint(Boolean thePrettyPrint);
@ -109,4 +105,8 @@ public interface IRestfulClient {
*/ */
void unregisterInterceptor(IClientInterceptor theInterceptor); void unregisterInterceptor(IClientInterceptor theInterceptor);
/**
* Configures what style of _format parameter should be used in requests
*/
void setFormatParamStyle(RequestFormatParamStyleEnum theRequestFormatParamStyle);
} }

View File

@ -20,49 +20,11 @@ package ca.uhn.fhir.rest.client.impl;
* #L% * #L%
*/ */
import static org.apache.commons.lang3.StringUtils.isNotBlank; import ca.uhn.fhir.context.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import ca.uhn.fhir.rest.api.CacheControlDirective;
import ca.uhn.fhir.util.XmlDetectionUtil;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition;
import ca.uhn.fhir.context.BaseRuntimeElementDefinition;
import ca.uhn.fhir.context.FhirContext;
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.Constants; import ca.uhn.fhir.rest.api.*;
import ca.uhn.fhir.rest.api.EncodingEnum; import ca.uhn.fhir.rest.client.api.*;
import ca.uhn.fhir.rest.api.SummaryEnum;
import ca.uhn.fhir.rest.client.api.IClientInterceptor;
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.IRestfulClientFactory;
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
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;
import ca.uhn.fhir.rest.client.exceptions.NonFhirResponseException; import ca.uhn.fhir.rest.client.exceptions.NonFhirResponseException;
@ -72,7 +34,19 @@ import ca.uhn.fhir.rest.client.method.IClientResponseHandlerHandlesBinary;
import ca.uhn.fhir.rest.client.method.MethodUtil; import ca.uhn.fhir.rest.client.method.MethodUtil;
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException; import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
import ca.uhn.fhir.util.OperationOutcomeUtil; import ca.uhn.fhir.util.OperationOutcomeUtil;
import ca.uhn.fhir.util.XmlUtil; import ca.uhn.fhir.util.XmlDetectionUtil;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.api.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.StringReader;
import java.util.*;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
public abstract class BaseClient implements IRestfulClient { public abstract class BaseClient implements IRestfulClient {
@ -86,16 +60,17 @@ 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 IHttpClient myClient; private final IHttpClient myClient;
private final RestfulClientFactory myFactory;
private final String myUrlBase;
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 List<IClientInterceptor> myInterceptors = new ArrayList<IClientInterceptor>(); private List<IClientInterceptor> myInterceptors = new ArrayList<IClientInterceptor>();
private boolean myKeepResponses = false; private boolean myKeepResponses = false;
private IHttpResponse 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 RequestFormatParamStyleEnum myRequestFormatParamStyle = RequestFormatParamStyleEnum.SHORT;
BaseClient(IHttpClient theClient, String theUrlBase, RestfulClientFactory theFactory) { BaseClient(IHttpClient theClient, String theUrlBase, RestfulClientFactory theFactory) {
super(); super();
@ -121,11 +96,13 @@ public abstract class BaseClient implements IRestfulClient {
protected Map<String, List<String>> createExtraParams() { protected Map<String, List<String>> createExtraParams() {
HashMap<String, List<String>> retVal = new LinkedHashMap<String, List<String>>(); HashMap<String, List<String>> retVal = new LinkedHashMap<String, List<String>>();
if (myRequestFormatParamStyle == RequestFormatParamStyleEnum.SHORT) {
if (getEncoding() == EncodingEnum.XML) { if (getEncoding() == EncodingEnum.XML) {
retVal.put(Constants.PARAM_FORMAT, Collections.singletonList("xml")); retVal.put(Constants.PARAM_FORMAT, Collections.singletonList("xml"));
} else if (getEncoding() == EncodingEnum.JSON) { } else if (getEncoding() == EncodingEnum.JSON) {
retVal.put(Constants.PARAM_FORMAT, Collections.singletonList("json")); retVal.put(Constants.PARAM_FORMAT, Collections.singletonList("json"));
} }
}
if (isPrettyPrint()) { if (isPrettyPrint()) {
retVal.put(Constants.PARAM_PRETTY, Collections.singletonList(Constants.PARAM_PRETTY_VALUE_TRUE)); retVal.put(Constants.PARAM_PRETTY, Collections.singletonList(Constants.PARAM_PRETTY_VALUE_TRUE));
@ -150,6 +127,17 @@ public abstract class BaseClient implements IRestfulClient {
return myEncoding; return myEncoding;
} }
/**
* Sets the encoding that will be used on requests. Default is <code>null</code>, which means the client will not
* explicitly request an encoding. (This is perfectly acceptable behaviour according to the FHIR specification. In
* this case, the server will choose which encoding to return, and the client can handle either XML or JSON)
*/
@Override
public void setEncoding(EncodingEnum theEncoding) {
myEncoding = theEncoding;
// return this;
}
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
@ -192,10 +180,21 @@ public abstract class BaseClient implements IRestfulClient {
return mySummary; return mySummary;
} }
@Override
public void setSummary(SummaryEnum theSummary) {
mySummary = theSummary;
}
public String getUrlBase() { public String getUrlBase() {
return myUrlBase; return myUrlBase;
} }
@Override
public void setFormatParamStyle(RequestFormatParamStyleEnum theRequestFormatParamStyle) {
Validate.notNull(theRequestFormatParamStyle, "theRequestFormatParamStyle must not be null");
myRequestFormatParamStyle = theRequestFormatParamStyle;
}
<T> T invokeClient(FhirContext theContext, IClientResponseHandler<T> binding, BaseHttpClientInvocation clientInvocation) { <T> T invokeClient(FhirContext theContext, IClientResponseHandler<T> binding, BaseHttpClientInvocation clientInvocation) {
return invokeClient(theContext, binding, clientInvocation, false); return invokeClient(theContext, binding, clientInvocation, false);
} }
@ -219,12 +218,14 @@ public abstract class BaseClient implements IRestfulClient {
Map<String, List<String>> params = createExtraParams(); Map<String, List<String>> params = createExtraParams();
if (clientInvocation instanceof HttpGetClientInvocation) { if (clientInvocation instanceof HttpGetClientInvocation) {
if (myRequestFormatParamStyle == RequestFormatParamStyleEnum.SHORT) {
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()));
@ -397,6 +398,13 @@ public abstract class BaseClient implements IRestfulClient {
return myKeepResponses; return myKeepResponses;
} }
/**
* For now, this is a part of the internal API of HAPI - Use with caution as this method may change!
*/
public void setKeepResponses(boolean theKeepResponses) {
myKeepResponses = theKeepResponses;
}
/** /**
* Returns the pretty print flag, which is a request to the server for it to return "pretty printed" responses. Note * Returns the pretty print flag, which is a request to the server for it to return "pretty printed" responses. Note
* that this is currently a non-standard flag (_pretty) which is supported only by HAPI based servers (and any other * that this is currently a non-standard flag (_pretty) which is supported only by HAPI based servers (and any other
@ -406,6 +414,17 @@ public abstract class BaseClient implements IRestfulClient {
return Boolean.TRUE.equals(myPrettyPrint); return Boolean.TRUE.equals(myPrettyPrint);
} }
/**
* Sets the pretty print flag, which is a request to the server for it to return "pretty printed" responses. Note
* that this is currently a non-standard flag (_pretty) which is supported only by HAPI based servers (and any other
* servers which might implement it).
*/
@Override
public void setPrettyPrint(Boolean thePrettyPrint) {
myPrettyPrint = thePrettyPrint;
// return this;
}
private void keepResponseAndLogIt(boolean theLogRequestAndResponse, IHttpResponse response, String responseString) { private void keepResponseAndLogIt(boolean theLogRequestAndResponse, IHttpResponse response, String responseString) {
if (myKeepResponses) { if (myKeepResponses) {
myLastResponse = response; myLastResponse = response;
@ -438,55 +457,12 @@ public abstract class BaseClient implements IRestfulClient {
myDontValidateConformance = theDontValidateConformance; myDontValidateConformance = theDontValidateConformance;
} }
/**
* Sets the encoding that will be used on requests. Default is <code>null</code>, which means the client will not
* explicitly request an encoding. (This is perfectly acceptable behaviour according to the FHIR specification. In
* this case, the server will choose which encoding to return, and the client can handle either XML or JSON)
*/
@Override
public void setEncoding(EncodingEnum theEncoding) {
myEncoding = theEncoding;
// return this;
}
/**
* For now, this is a part of the internal API of HAPI - Use with caution as this method may change!
*/
public void setKeepResponses(boolean theKeepResponses) {
myKeepResponses = theKeepResponses;
}
/**
* Sets the pretty print flag, which is a request to the server for it to return "pretty printed" responses. Note
* that this is currently a non-standard flag (_pretty) which is supported only by HAPI based servers (and any other
* servers which might implement it).
*/
@Override
public void setPrettyPrint(Boolean thePrettyPrint) {
myPrettyPrint = thePrettyPrint;
// return this;
}
@Override
public void setSummary(SummaryEnum theSummary) {
mySummary = theSummary;
}
@Override @Override
public void unregisterInterceptor(IClientInterceptor theInterceptor) { public void unregisterInterceptor(IClientInterceptor theInterceptor) {
Validate.notNull(theInterceptor, "Interceptor can not be null"); Validate.notNull(theInterceptor, "Interceptor can not be null");
myInterceptors.remove(theInterceptor); myInterceptors.remove(theInterceptor);
} }
static ArrayList<Class<? extends IBaseResource>> toTypeList(Class<? extends IBaseResource> thePreferResponseType) {
ArrayList<Class<? extends IBaseResource>> preferResponseTypes = null;
if (thePreferResponseType != null) {
preferResponseTypes = new ArrayList<Class<? extends IBaseResource>>(1);
preferResponseTypes.add(thePreferResponseType);
}
return preferResponseTypes;
}
protected final class ResourceResponseHandler<T extends IBaseResource> implements IClientResponseHandler<T> { protected final class ResourceResponseHandler<T extends IBaseResource> implements IClientResponseHandler<T> {
private boolean myAllowHtmlResponse; private boolean myAllowHtmlResponse;
@ -568,4 +544,13 @@ public abstract class BaseClient implements IRestfulClient {
} }
} }
static ArrayList<Class<? extends IBaseResource>> toTypeList(Class<? extends IBaseResource> thePreferResponseType) {
ArrayList<Class<? extends IBaseResource>> preferResponseTypes = null;
if (thePreferResponseType != null) {
preferResponseTypes = new ArrayList<Class<? extends IBaseResource>>(1);
preferResponseTypes.add(thePreferResponseType);
}
return preferResponseTypes;
}
} }

View File

@ -1,17 +1,13 @@
package ca.uhn.fhir.rest.client; package ca.uhn.fhir.rest.client;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.rest.api.Constants; import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.MethodOutcome; import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.RequestFormatParamStyleEnum;
import ca.uhn.fhir.rest.client.api.IGenericClient; import ca.uhn.fhir.rest.client.api.IGenericClient;
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum; import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
import ca.uhn.fhir.util.RandomServerPortProvider; import ca.uhn.fhir.util.RandomServerPortProvider;
import ca.uhn.fhir.util.TestUtil; import ca.uhn.fhir.util.TestUtil;
import ca.uhn.fhir.util.VersionUtil;
import org.apache.commons.io.IOUtils;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpUriRequest;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.servlet.ServletHolder;
@ -20,9 +16,7 @@ import org.junit.AfterClass;
import org.junit.Before; import org.junit.Before;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import org.mockito.ArgumentCaptor;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
@ -40,8 +34,9 @@ public class ClientHeadersR4Test {
private static Server ourServer; private static Server ourServer;
private static String ourServerBase; private static String ourServerBase;
private static HashMap<String, List<String>> ourHeaders; private static HashMap<String, List<String>> ourHeaders;
private static IGenericClient ourClient; private static HashMap<String, String[]> ourParams;
private static String ourMethod; private static String ourMethod;
private IGenericClient myClient;
@Before @Before
public void before() { public void before() {
@ -49,34 +44,125 @@ public class ClientHeadersR4Test {
ourMethod = null; ourMethod = null;
} }
private String expectedUserAgent() {
return "HAPI-FHIR/" + VersionUtil.getVersion() + " (FHIR Client; FHIR " + FhirVersionEnum.R4.getFhirVersionString() + "/R4; apache)";
}
private byte[] extractBodyAsByteArray(ArgumentCaptor<HttpUriRequest> capt) throws IOException {
byte[] body = IOUtils.toByteArray(((HttpEntityEnclosingRequestBase) capt.getAllValues().get(0)).getEntity().getContent());
return body;
}
private String extractBodyAsString(ArgumentCaptor<HttpUriRequest> capt) throws IOException {
String body = IOUtils.toString(((HttpEntityEnclosingRequestBase) capt.getAllValues().get(0)).getEntity().getContent(), "UTF-8");
return body;
}
@Test @Test
public void testCreateWithPreferRepresentationServerReturnsResource() throws Exception { public void testReadXml() {
myClient
.read()
.resource("Patient")
.withId(123L)
.encodedXml()
.execute();
assertEquals("application/fhir+xml;q=1.0, application/xml+fhir;q=0.9", ourHeaders.get(Constants.HEADER_ACCEPT).get(0));
assertEquals("xml", ourParams.get(Constants.PARAM_FORMAT)[0]);
}
@Test
public void testReadXmlNoParam() {
myClient.setFormatParamStyle(RequestFormatParamStyleEnum.NONE);
myClient
.read()
.resource("Patient")
.withId(123L)
.encodedXml()
.execute();
assertEquals("application/fhir+xml;q=1.0, application/xml+fhir;q=0.9", ourHeaders.get(Constants.HEADER_ACCEPT).get(0));
assertEquals(null, ourParams.get(Constants.PARAM_FORMAT));
}
@Test
public void testReadJson() {
myClient
.read()
.resource("Patient")
.withId(123L)
.encodedJson()
.execute();
assertEquals("application/fhir+json;q=1.0, application/json+fhir;q=0.9", ourHeaders.get(Constants.HEADER_ACCEPT).get(0));
assertEquals("json", ourParams.get(Constants.PARAM_FORMAT)[0]);
}
@Test
public void testReadJsonNoParam() {
myClient.setFormatParamStyle(RequestFormatParamStyleEnum.NONE);
myClient
.read()
.resource("Patient")
.withId(123L)
.encodedJson()
.execute();
assertEquals("application/fhir+json;q=1.0, application/json+fhir;q=0.9", ourHeaders.get(Constants.HEADER_ACCEPT).get(0));
assertEquals(null, ourParams.get(Constants.PARAM_FORMAT));
}
@Test
public void testReadXmlDisable() {
myClient
.read()
.resource("Patient")
.withId(123L)
.encodedXml()
.execute();
assertEquals("application/fhir+xml;q=1.0, application/xml+fhir;q=0.9", ourHeaders.get(Constants.HEADER_ACCEPT).get(0));
assertEquals("xml", ourParams.get(Constants.PARAM_FORMAT)[0]);
}
@Test
public void testCreateWithPreferRepresentationServerReturnsResource() {
final Patient resp1 = new Patient(); final Patient resp1 = new Patient();
resp1.setActive(true); resp1.setActive(true);
MethodOutcome resp = ourClient.create().resource(resp1).execute(); MethodOutcome resp = myClient.create().resource(resp1).execute();
assertNotNull(resp); assertNotNull(resp);
assertEquals(1, ourHeaders.get(Constants.HEADER_CONTENT_TYPE).size()); assertEquals(1, ourHeaders.get(Constants.HEADER_CONTENT_TYPE).size());
assertEquals("application/fhir+xml; charset=UTF-8", ourHeaders.get(Constants.HEADER_CONTENT_TYPE).get(0)); assertEquals("application/fhir+xml; charset=UTF-8", ourHeaders.get(Constants.HEADER_CONTENT_TYPE).get(0));
} }
@Before
public void beforeCreateClient() {
myClient = ourCtx.newRestfulGenericClient(ourServerBase);
}
private static class TestServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws IOException {
if (ourHeaders != null) {
fail();
}
ourHeaders = new HashMap<>();
ourParams = new HashMap<>(req.getParameterMap());
ourMethod = req.getMethod();
Enumeration<String> names = req.getHeaderNames();
while (names.hasMoreElements()) {
String nextName = names.nextElement();
ourHeaders.put(nextName, new ArrayList<>());
Enumeration<String> values = req.getHeaders(nextName);
while (values.hasMoreElements()) {
ourHeaders.get(nextName).add(values.nextElement());
}
}
resp.setStatus(200);
if (req.getMethod().equals("GET")) {
resp.setContentType("application/json");
resp.getWriter().append("{\"resourceType\":\"Patient\"}");
resp.getWriter().close();
}
}
}
@AfterClass @AfterClass
public static void afterClassClearContext() { public static void afterClassClearContext() {
TestUtil.clearAllStaticFieldsForUnitTest(); TestUtil.clearAllStaticFieldsForUnitTest();
@ -94,7 +180,6 @@ public class ClientHeadersR4Test {
ourServerBase = "http://localhost:" + myPort + "/fhir/context"; ourServerBase = "http://localhost:" + myPort + "/fhir/context";
ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER); ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
ourClient = ourCtx.newRestfulGenericClient(ourServerBase);
ServletHolder servletHolder = new ServletHolder(); ServletHolder servletHolder = new ServletHolder();
servletHolder.setServlet(new TestServlet()); servletHolder.setServlet(new TestServlet());
@ -105,29 +190,4 @@ public class ClientHeadersR4Test {
} }
private static class TestServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
if (ourHeaders != null) {
fail();
}
ourHeaders = new HashMap<>();
ourMethod = req.getMethod();
Enumeration<String> names = req.getHeaderNames();
while (names.hasMoreElements()) {
String nextName = names.nextElement();
ourHeaders.put(nextName, new ArrayList<String>());
Enumeration<String> values = req.getHeaders(nextName);
while (values.hasMoreElements()) {
ourHeaders.get(nextName).add(values.nextElement());
}
}
resp.setStatus(200);
}
}
} }

View File

@ -171,7 +171,12 @@
<action type="fix" issue="1071" dev="volsch"> <action type="fix" issue="1071" dev="volsch">
When restful reponses tried to return multiple instances of the same response header, When restful reponses tried to return multiple instances of the same response header,
some instances were discarded. Thanks to Volker Schmidt for the pull request! some instances were discarded. Thanks to Volker Schmidt for the pull request!
</action>" </action>
<action type="add">
The REST client now allows for configurable behaviour as to whether a
<![CDATA[<code>_format</code>]]>
parameter should be included in requests.
</action>
</release> </release>
<release version="3.5.0" date="2018-09-17"> <release version="3.5.0" date="2018-09-17">