Fix #60 - Client did not correctly send charset declaration as a part of

content-type header on POST/PUT requests
This commit is contained in:
James Agnew 2014-12-16 11:09:26 -05:00
parent c10f501fdc
commit 326aa515a9
7 changed files with 375 additions and 295 deletions

View File

@ -101,9 +101,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(GenericClient.class);
private FhirContext myContext;
private HttpRequestBase myLastRequest;
private boolean myLogRequestAndResponse;
/**

View File

@ -215,14 +215,14 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
contents = parser.encodeResourceToString(myResource);
contentType = encoding.getResourceContentType();
}
entity = new StringEntity(contents, ContentType.create(contentType, "UTF-8"));
entity = new StringEntity(contents, ContentType.create(contentType, Constants.CHARSET_UTF_8));
}
HttpRequestBase retVal = createRequest(url, entity);
super.addHeadersToRequest(retVal);
if (contentType != null) {
retVal.addHeader(Constants.HEADER_CONTENT_TYPE, contentType);
retVal.addHeader(Constants.HEADER_CONTENT_TYPE, contentType + Constants.HEADER_SUFFIX_CT_UTF_8);
}
return retVal;

View File

@ -44,6 +44,7 @@ public class Constants {
public static final Map<String, EncodingEnum> FORMAT_VAL_TO_ENCODING;
public static final Set<String> FORMAT_VAL_XML;
public static final String FORMAT_XML = "xml";
public static final String HEADER_SUFFIX_CT_UTF_8 = "; charset=UTF-8";
public static final String HEADER_ACCEPT = "Accept";
public static final String HEADER_ACCEPT_ENCODING = "Accept-Encoding";
public static final String HEADER_AUTHORIZATION = "Authorization";

View File

@ -3,6 +3,7 @@ package ca.uhn.fhir.jpa.dao;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
@ -1139,6 +1140,24 @@ public class FhirResourceDaoTest {
}
/**
* Test for issue #60
*/
@Test
public void testStoreUtf8Characters() throws Exception {
String name = "測試醫院";
Organization org = new Organization();
org.setName(new String(name.getBytes(), "UTF-8"));
org.addIdentifier("urn:system", "testStoreUtf8Characters_01");
IdDt orgId = ourOrganizationDao.create(org).getId();
Organization returned = ourOrganizationDao.read(orgId);
String val = ourFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(returned);
ourLog.info(val);
assertThat(val, containsString("<name value=\"測試醫院\"/>"));
}
/**
* Test for #62
*/

View File

@ -60,15 +60,43 @@ public class CompleteResourceProviderTest {
private static ClassPathXmlApplicationContext ourAppCtx;
private static IGenericClient ourClient;
private static FhirContext ourCtx;
private static FhirContext ourFhirCtx;
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(CompleteResourceProviderTest.class);
private static IFhirResourceDao<Observation> ourObservationDao;
private static IFhirResourceDao<Patient> ourPatientDao;
private static IFhirResourceDao<Questionnaire> ourQuestionnaireDao;
private static Server ourServer;
private static IFhirResourceDao<Organization> ourOrganizationDao;
// private static JpaConformanceProvider ourConfProvider;
/**
* Test for issue #60
*/
@Test
public void testStoreUtf8Characters() throws Exception {
String name = "測試醫院";
Organization org = new Organization();
org.setName(name);
org.addIdentifier("urn:system", "testStoreUtf8Characters_01");
IdDt orgId = ourClient.create().resource(org).prettyPrint().encodedXml().execute().getId();
// Read back directly from the DAO
{
Organization returned = ourOrganizationDao.read(orgId);
String val = ourFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(returned);
ourLog.info(val);
assertThat(val, containsString("<name value=\"測試醫院\"/>"));
}
// Read back through the HTTP API
{
Organization returned = ourClient.read(Organization.class, orgId);
String val = ourFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(returned);
ourLog.info(val);
assertThat(val, containsString("<name value=\"測試醫院\"/>"));
}
}
/**
* See issue #52
*/
@ -143,7 +171,6 @@ public class CompleteResourceProviderTest {
}
private void delete(String theResourceType, String theParamName, String theParamValue) {
Bundle resources = ourClient.search().forResource(theResourceType).where(new StringClientParam(theParamName).matches().value(theParamValue)).execute();
for (IResource next : resources.toListOfResources()) {
@ -445,27 +472,27 @@ public class CompleteResourceProviderTest {
EncounterResourceProvider encounterRp = new EncounterResourceProvider();
encounterRp.setDao(encounterDao);
IFhirResourceDao<Organization> organizationDao = (IFhirResourceDao<Organization>) ourAppCtx.getBean("myOrganizationDao", IFhirResourceDao.class);
ourOrganizationDao = (IFhirResourceDao<Organization>) ourAppCtx.getBean("myOrganizationDao", IFhirResourceDao.class);
OrganizationResourceProvider organizationRp = new OrganizationResourceProvider();
organizationRp.setDao(organizationDao);
organizationRp.setDao(ourOrganizationDao);
IFhirResourceDao<ImagingStudy> imagingStudyDao = (IFhirResourceDao<ImagingStudy>) ourAppCtx.getBean("myImagingStudyDao", IFhirResourceDao.class);
ImagingStudyResourceProvider imagingStudyRp = new ImagingStudyResourceProvider();
imagingStudyRp.setDao(imagingStudyDao);
IFhirResourceDao<DiagnosticOrder> diagnosticOrderDao =ourAppCtx.getBean("myDiagnosticOrderDao", IFhirResourceDao.class);
IFhirResourceDao<DiagnosticOrder> diagnosticOrderDao = ourAppCtx.getBean("myDiagnosticOrderDao", IFhirResourceDao.class);
DiagnosticOrderResourceProvider diagnosticOrderRp = new DiagnosticOrderResourceProvider();
diagnosticOrderRp.setDao(diagnosticOrderDao);
IFhirResourceDao<DocumentManifest> documentManifestDao =ourAppCtx.getBean("myDocumentManifestDao", IFhirResourceDao.class);
IFhirResourceDao<DocumentManifest> documentManifestDao = ourAppCtx.getBean("myDocumentManifestDao", IFhirResourceDao.class);
DocumentManifestResourceProvider documentManifestRp = new DocumentManifestResourceProvider();
documentManifestRp.setDao(documentManifestDao);
IFhirResourceDao<DocumentReference> documentReferenceDao =ourAppCtx.getBean("myDocumentReferenceDao", IFhirResourceDao.class);
IFhirResourceDao<DocumentReference> documentReferenceDao = ourAppCtx.getBean("myDocumentReferenceDao", IFhirResourceDao.class);
DocumentReferenceResourceProvider documentReferenceRp = new DocumentReferenceResourceProvider();
documentReferenceRp.setDao(documentReferenceDao);
restServer.setResourceProviders(diagnosticOrderRp, documentManifestRp, documentReferenceRp, encounterRp, locationRp, patientRp, questionnaireRp, observationRp, organizationRp, imagingStudyRp);
restServer.setResourceProviders(diagnosticOrderRp, documentManifestRp, documentReferenceRp, encounterRp, locationRp, patientRp, questionnaireRp, organizationRp, imagingStudyRp);
restServer.getFhirContext().setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator());
IFhirSystemDao systemDao = (IFhirSystemDao) ourAppCtx.getBean("mySystemDao", IFhirSystemDao.class);
@ -490,10 +517,10 @@ public class CompleteResourceProviderTest {
ourServer.start();
}
ourCtx = restServer.getFhirContext();
ourFhirCtx = restServer.getFhirContext();
// ourCtx.getRestfulClientFactory().setProxy("localhost", 8888);
ourClient = ourCtx.newRestfulGenericClient(serverBase);
ourClient = ourFhirCtx.newRestfulGenericClient(serverBase);
// ourClient = ourCtx.newRestfulGenericClient("http://fhir.healthintersections.com.au/open");
// ourClient = ourCtx.newRestfulGenericClient("https://fhir.orionhealth.com/blaze/fhir");
// ourClient = ourCtx.newRestfulGenericClient("http://spark.furore.com/fhir");

View File

@ -70,6 +70,11 @@ public class GenericClientTest {
myHttpResponse = mock(HttpResponse.class, new ReturnsDeepStubs());
}
private String extractBody(ArgumentCaptor<HttpUriRequest> capt, int count) throws IOException {
String body = IOUtils.toString(((HttpEntityEnclosingRequestBase) capt.getAllValues().get(count)).getEntity().getContent(), "UTF-8");
return body;
}
private String getPatientFeedWithOneResult() {
//@formatter:off
String msg = "<feed xmlns=\"http://www.w3.org/2005/Atom\">\n" +
@ -114,45 +119,51 @@ public class GenericClientTest {
return msg;
}
@Test
public void testSearchByCompartment() throws Exception {
String msg = getPatientFeedWithOneResult();
@Test
public void testCreateWithStringAutoDetectsEncoding() throws Exception {
Patient p1 = new Patient();
p1.addIdentifier("foo:bar", "12345");
p1.addName().addFamily("Smith").addGiven("John");
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);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 201, "OK"));
when(myHttpResponse.getAllHeaders()).thenReturn(new Header[] { new BasicHeader(Constants.HEADER_LOCATION, "/Patient/44/_history/22") });
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://foo");
//@formatter:off
Bundle response = client
.search()
.forResource(Patient.class)
.withIdAndCompartment("123", "fooCompartment")
.where(Patient.BIRTHDATE.afterOrEquals().day("2011-01-02"))
.execute();
//@formatter:on
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
assertEquals("http://foo/Patient/123/fooCompartment?birthdate=%3E%3D2011-01-02", capt.getValue().getURI().toString());
assertEquals("PRP1660", response.getResources(Patient.class).get(0).getIdentifier().get(0).getValue().getValue());
int count = 0;
client.create().resource(myCtx.newXmlParser().encodeResourceToString(p1)).execute();
assertEquals(1, capt.getAllValues().get(count).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentType(), capt.getAllValues().get(count).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertThat(extractBody(capt, count), containsString("value=\"John\""));
count++;
try {
//@formatter:off
client
.search()
.forResource(Patient.class)
.withIdAndCompartment("", "fooCompartment")
.where(Patient.BIRTHDATE.afterOrEquals().day("2011-01-02"))
.execute();
//@formatter:on
fail();
} catch (InvalidRequestException e) {
assertThat(e.toString(), containsString("null or empty for compartment"));
}
client.create().resource(myCtx.newJsonParser().encodeResourceToString(p1)).execute();
assertEquals(1, capt.getAllValues().get(count).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.JSON.getResourceContentType(), capt.getAllValues().get(count).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertThat(extractBody(capt, count), containsString("[\"John\"]"));
count++;
/*
* 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();
assertEquals(1, capt.getAllValues().get(count).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.JSON.getResourceContentType(), 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();
assertEquals(1, capt.getAllValues().get(count).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentType(), capt.getAllValues().get(count).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertThat(extractBody(capt, count), containsString("value=\"John\""));
count++;
}
@ -210,104 +221,6 @@ public class GenericClientTest {
count++;
}
@Test
public void testCreateWithStringAutoDetectsEncoding() throws Exception {
Patient p1 = new Patient();
p1.addIdentifier("foo:bar", "12345");
p1.addName().addFamily("Smith").addGiven("John");
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 201, "OK"));
when(myHttpResponse.getAllHeaders()).thenReturn(new Header[] { new BasicHeader(Constants.HEADER_LOCATION, "/Patient/44/_history/22") });
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");
int count = 0;
client.create().resource(myCtx.newXmlParser().encodeResourceToString(p1)).execute();
assertEquals(1, capt.getAllValues().get(count).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentType(), 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();
assertEquals(1, capt.getAllValues().get(count).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.JSON.getResourceContentType(), capt.getAllValues().get(count).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertThat(extractBody(capt, count), containsString("[\"John\"]"));
count++;
/*
* 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();
assertEquals(1, capt.getAllValues().get(count).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.JSON.getResourceContentType(), 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();
assertEquals(1, capt.getAllValues().get(count).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentType(), capt.getAllValues().get(count).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertThat(extractBody(capt, count), containsString("value=\"John\""));
count++;
}
private String extractBody(ArgumentCaptor<HttpUriRequest> capt, int count) throws IOException {
String body = IOUtils.toString(((HttpEntityEnclosingRequestBase) capt.getAllValues().get(count)).getEntity().getContent());
return body;
}
@Test
public void testUpdateWithStringAutoDetectsEncoding() throws Exception {
Patient p1 = new Patient();
p1.addIdentifier("foo:bar", "12345");
p1.addName().addFamily("Smith").addGiven("John");
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 201, "OK"));
when(myHttpResponse.getAllHeaders()).thenReturn(new Header[] { new BasicHeader(Constants.HEADER_LOCATION, "/Patient/44/_history/22") });
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");
int count = 0;
client.update().resource(myCtx.newXmlParser().encodeResourceToString(p1)).withId("1").execute();
assertEquals(1, capt.getAllValues().get(count).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentType(), 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();
assertEquals(1, capt.getAllValues().get(count).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.JSON.getResourceContentType(), capt.getAllValues().get(count).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertThat(extractBody(capt, count), containsString("[\"John\"]"));
count++;
/*
* 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();
assertEquals(1, capt.getAllValues().get(count).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.JSON.getResourceContentType(), 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();
assertEquals(1, capt.getAllValues().get(count).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentType(), capt.getAllValues().get(count).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertThat(extractBody(capt, count), containsString("value=\"John\""));
count++;
}
@Test
public void testCreateWithTagNonFluent() throws Exception {
@ -338,6 +251,34 @@ public class GenericClientTest {
assertEquals("urn:happytag; label=\"This is a happy resource\"; scheme=\"http://hl7.org/fhir/tag\"", catH.getValue());
}
/**
* Test for issue #60
*/
@Test
public void testCreateWithUtf8Characters() throws Exception {
String name = "測試醫院";
Organization org = new Organization();
org.setName(name);
org.addIdentifier("urn:system", "testCreateWithUtf8Characters_01");
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 201, "OK"));
when(myHttpResponse.getAllHeaders()).thenReturn(new Header[] { new BasicHeader(Constants.HEADER_LOCATION, "/Patient/44/_history/22") });
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");
int count = 0;
client.create().resource(org).prettyPrint().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("<name value=\"測試醫院\"/>"));
count++;
}
@Test
public void testDelete() throws Exception {
OperationOutcome oo = new OperationOutcome();
@ -472,36 +413,6 @@ public class GenericClientTest {
}
@Test
public void testVReadWithAbsoluteUrl() throws Exception {
String msg = getResourceResult();
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
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")));
Header[] headers = new Header[] { new BasicHeader(Constants.HEADER_LAST_MODIFIED, "Wed, 15 Nov 1995 04:58:08 GMT"),
new BasicHeader(Constants.HEADER_CONTENT_LOCATION, "http://foo.com/Patient/123/_history/2333"),
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");
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"));
assertEquals("http://somebase.com/path/to/base/Patient/1234/_history/2222", capt.getAllValues().get(0).getURI().toString());
try {
client.vread(Patient.class, new IdDt("http://somebase.com/path/to/base/Patient/1234"));
fail();
} catch (IllegalArgumentException e) {
assertThat(e.getMessage(), containsString("No version specified in URL"));
}
}
@SuppressWarnings("unused")
@Test
public void testSearchAllResources() throws Exception {
@ -527,6 +438,80 @@ public class GenericClientTest {
}
@SuppressWarnings("unused")
@Test
public void testSearchAutomaticallyUsesPost() throws Exception {
String msg = getPatientFeedWithOneResult();
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
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")));
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
String longValue = StringUtils.leftPad("", 20000, 'B');
//@formatter:off
Bundle response = client.search()
.forResource("Patient")
.where(Patient.NAME.matches().value(longValue))
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/Patient/_search", capt.getValue().getURI().toString());
HttpEntityEnclosingRequestBase enc = (HttpEntityEnclosingRequestBase) capt.getValue();
UrlEncodedFormEntity ent = (UrlEncodedFormEntity) enc.getEntity();
String string = IOUtils.toString(ent.getContent());
ourLog.info(string);
assertEquals("name=" + longValue, string);
}
@Test
public void testSearchByCompartment() throws Exception {
String msg = getPatientFeedWithOneResult();
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);
IGenericClient client = myCtx.newRestfulGenericClient("http://foo");
//@formatter:off
Bundle response = client
.search()
.forResource(Patient.class)
.withIdAndCompartment("123", "fooCompartment")
.where(Patient.BIRTHDATE.afterOrEquals().day("2011-01-02"))
.execute();
//@formatter:on
assertEquals("http://foo/Patient/123/fooCompartment?birthdate=%3E%3D2011-01-02", capt.getValue().getURI().toString());
assertEquals("PRP1660", response.getResources(Patient.class).get(0).getIdentifier().get(0).getValue().getValue());
try {
//@formatter:off
client
.search()
.forResource(Patient.class)
.withIdAndCompartment("", "fooCompartment")
.where(Patient.BIRTHDATE.afterOrEquals().day("2011-01-02"))
.execute();
//@formatter:on
fail();
} catch (InvalidRequestException e) {
assertThat(e.toString(), containsString("null or empty for compartment"));
}
}
@SuppressWarnings("unused")
@Test
public void testSearchByComposite() throws Exception {
@ -555,32 +540,6 @@ public class GenericClientTest {
}
@SuppressWarnings("unused")
@Test
public void testSearchWithClientEncodingAndPrettyPrintConfig() throws Exception {
String msg = getPatientFeedWithOneResult();
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
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")));
GenericClient client = (GenericClient) myCtx.newRestfulGenericClient("http://example.com/fhir");
client.setPrettyPrint(true);
client.setEncoding(EncodingEnum.JSON);
//@formatter:off
Bundle response = client.search()
.forResource(Patient.class)
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/Patient?_format=json&_pretty=true", capt.getValue().getURI().toString());
}
@SuppressWarnings("unused")
@Test
public void testSearchByDate() throws Exception {
@ -614,55 +573,6 @@ public class GenericClientTest {
}
@Test
public void testSearchWithAbsoluteUrl() throws Exception {
String msg = getPatientFeedWithOneResult();
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
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")));
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
Bundle response = client
.search(new UriDt(
"http://example.com/fhir/Patient?birthdate=%3C%3D2012-01-22&birthdate=%3E2011-01-01&_include=Patient.managingOrganization&_sort%3Aasc=birthdate&_sort%3Adesc=name&_count=123&_format=json"));
assertEquals(
"http://example.com/fhir/Patient?birthdate=%3C%3D2012-01-22&birthdate=%3E2011-01-01&_include=Patient.managingOrganization&_sort%3Aasc=birthdate&_sort%3Adesc=name&_count=123&_format=json",
capt.getValue().getURI().toString());
assertEquals(1, response.size());
}
@Test
public void testSearchWithAbsoluteUrlAndType() throws Exception {
String msg = getPatientFeedWithOneResult();
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
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")));
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
Bundle response = client
.search(Patient.class,
new UriDt(
"http://example.com/fhir/Patient?birthdate=%3C%3D2012-01-22&birthdate=%3E2011-01-01&_include=Patient.managingOrganization&_sort%3Aasc=birthdate&_sort%3Adesc=name&_count=123&_format=json"));
assertEquals(
"http://example.com/fhir/Patient?birthdate=%3C%3D2012-01-22&birthdate=%3E2011-01-01&_include=Patient.managingOrganization&_sort%3Aasc=birthdate&_sort%3Adesc=name&_count=123&_format=json",
capt.getValue().getURI().toString());
assertEquals(1, response.size());
}
@SuppressWarnings("unused")
@Test
public void testSearchByNumberExact() throws Exception {
@ -868,6 +778,31 @@ public class GenericClientTest {
}
@SuppressWarnings("unused")
@Test
public void testSearchUsingGetSearch() throws Exception {
String msg = getPatientFeedWithOneResult();
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
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")));
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
//@formatter:off
Bundle response = client.search()
.forResource("Patient")
.where(Patient.NAME.matches().value("james"))
.usingStyle(SearchStyleEnum.GET_WITH_SEARCH)
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/Patient/_search?name=james", capt.getValue().getURI().toString());
}
@SuppressWarnings("unused")
@Test
public void testSearchUsingPost() throws Exception {
@ -899,9 +834,8 @@ public class GenericClientTest {
assertEquals("name=james", string);
}
@SuppressWarnings("unused")
@Test
public void testSearchAutomaticallyUsesPost() throws Exception {
public void testSearchWithAbsoluteUrl() throws Exception {
String msg = getPatientFeedWithOneResult();
@ -913,27 +847,45 @@ public class GenericClientTest {
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
String longValue = StringUtils.leftPad("", 20000, 'B');
Bundle response = client
.search(new UriDt(
"http://example.com/fhir/Patient?birthdate=%3C%3D2012-01-22&birthdate=%3E2011-01-01&_include=Patient.managingOrganization&_sort%3Aasc=birthdate&_sort%3Adesc=name&_count=123&_format=json"));
//@formatter:off
Bundle response = client.search()
.forResource("Patient")
.where(Patient.NAME.matches().value(longValue))
.execute();
//@formatter:on
assertEquals(
"http://example.com/fhir/Patient?birthdate=%3C%3D2012-01-22&birthdate=%3E2011-01-01&_include=Patient.managingOrganization&_sort%3Aasc=birthdate&_sort%3Adesc=name&_count=123&_format=json",
capt.getValue().getURI().toString());
assertEquals("http://example.com/fhir/Patient/_search", capt.getValue().getURI().toString());
assertEquals(1, response.size());
}
HttpEntityEnclosingRequestBase enc = (HttpEntityEnclosingRequestBase) capt.getValue();
UrlEncodedFormEntity ent = (UrlEncodedFormEntity) enc.getEntity();
String string = IOUtils.toString(ent.getContent());
ourLog.info(string);
assertEquals("name=" + longValue, string);
@Test
public void testSearchWithAbsoluteUrlAndType() throws Exception {
String msg = getPatientFeedWithOneResult();
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
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")));
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
Bundle response = client
.search(Patient.class,
new UriDt(
"http://example.com/fhir/Patient?birthdate=%3C%3D2012-01-22&birthdate=%3E2011-01-01&_include=Patient.managingOrganization&_sort%3Aasc=birthdate&_sort%3Adesc=name&_count=123&_format=json"));
assertEquals(
"http://example.com/fhir/Patient?birthdate=%3C%3D2012-01-22&birthdate=%3E2011-01-01&_include=Patient.managingOrganization&_sort%3Aasc=birthdate&_sort%3Adesc=name&_count=123&_format=json",
capt.getValue().getURI().toString());
assertEquals(1, response.size());
}
@SuppressWarnings("unused")
@Test
public void testSearchUsingGetSearch() throws Exception {
public void testSearchWithClientEncodingAndPrettyPrintConfig() throws Exception {
String msg = getPatientFeedWithOneResult();
@ -943,17 +895,18 @@ 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");
GenericClient client = (GenericClient) myCtx.newRestfulGenericClient("http://example.com/fhir");
client.setPrettyPrint(true);
client.setEncoding(EncodingEnum.JSON);
//@formatter:off
Bundle response = client.search()
.forResource("Patient")
.where(Patient.NAME.matches().value("james"))
.usingStyle(SearchStyleEnum.GET_WITH_SEARCH)
.forResource(Patient.class)
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/Patient/_search?name=james", capt.getValue().getURI().toString());
assertEquals("http://example.com/fhir/Patient?_format=json&_pretty=true", capt.getValue().getURI().toString());
}
@SuppressWarnings("unused")
@ -1126,6 +1079,82 @@ public class GenericClientTest {
}
@Test
public void testUpdateWithStringAutoDetectsEncoding() throws Exception {
Patient p1 = new Patient();
p1.addIdentifier("foo:bar", "12345");
p1.addName().addFamily("Smith").addGiven("John");
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 201, "OK"));
when(myHttpResponse.getAllHeaders()).thenReturn(new Header[] { new BasicHeader(Constants.HEADER_LOCATION, "/Patient/44/_history/22") });
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");
int count = 0;
client.update().resource(myCtx.newXmlParser().encodeResourceToString(p1)).withId("1").execute();
assertEquals(1, capt.getAllValues().get(count).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentType(), 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();
assertEquals(1, capt.getAllValues().get(count).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.JSON.getResourceContentType(), capt.getAllValues().get(count).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertThat(extractBody(capt, count), containsString("[\"John\"]"));
count++;
/*
* 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();
assertEquals(1, capt.getAllValues().get(count).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.JSON.getResourceContentType(), 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();
assertEquals(1, capt.getAllValues().get(count).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentType(), capt.getAllValues().get(count).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertThat(extractBody(capt, count), containsString("value=\"John\""));
count++;
}
@Test
public void testVReadWithAbsoluteUrl() throws Exception {
String msg = getResourceResult();
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
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")));
Header[] headers = new Header[] { new BasicHeader(Constants.HEADER_LAST_MODIFIED, "Wed, 15 Nov 1995 04:58:08 GMT"),
new BasicHeader(Constants.HEADER_CONTENT_LOCATION, "http://foo.com/Patient/123/_history/2333"),
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");
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"));
assertEquals("http://somebase.com/path/to/base/Patient/1234/_history/2222", capt.getAllValues().get(0).getURI().toString());
try {
client.vread(Patient.class, new IdDt("http://somebase.com/path/to/base/Patient/1234"));
fail();
} catch (IllegalArgumentException e) {
assertThat(e.getMessage(), containsString("No version specified in URL"));
}
}
@BeforeClass
public static void beforeClass() {
myCtx = new FhirContext();

View File

@ -183,6 +183,12 @@
resources were present with a non-numeric identifier. Thanks to
Bill de Beaubien for reporting!
</action>
<action type="fix" issue="60">
Client requests which include a resource/bundle body (e.g. create,
update, transaction) were not including a charset in the content type
header, leading to servers incorrectly assuming ISO-8859/1. Thanks to
shvoidlee for reporting!
</action>
</release>
<release version="0.7" date="2014-Oct-23">
<action type="add" issue="30">