Allow fluent client users to execute a transaction using a string as

input
This commit is contained in:
James Agnew 2015-04-27 13:19:40 -04:00
parent e147c74df7
commit 5e8fe01af1
13 changed files with 296 additions and 735 deletions

View File

@ -369,7 +369,7 @@ public abstract class BaseClient implements IRestfulClient {
}
/**
* This method is an internal part of the HAPI API andmay change, use with caution. If you
* This method is an internal part of the HAPI API and may change, use with caution. If you
* want to disable the loading of conformance statements, use {@link IRestfulClientFactory#setServerValidationModeEnum(ServerValidationModeEnum)}
*/
public void setDontValidateConformance(boolean theDontValidateConformance) {

View File

@ -32,6 +32,7 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.http.client.HttpClient;
@ -575,23 +576,14 @@ public class GenericClient extends BaseClient implements IGenericClient {
}
protected IResource parseResourceBody(String theResourceBody) {
EncodingEnum encoding = null;
for (int i = 0; i < theResourceBody.length() && encoding == null; i++) {
switch (theResourceBody.charAt(i)) {
case '<':
encoding = EncodingEnum.XML;
break;
case '{':
encoding = EncodingEnum.JSON;
break;
}
}
EncodingEnum encoding = determineRawEncoding(theResourceBody);
if (encoding == null) {
throw new InvalidRequestException("FHIR client can't determine resource encoding");
}
return encoding.newParser(myContext).parseResource(theResourceBody);
}
@SuppressWarnings("unchecked")
@Override
public T prettyPrint() {
@ -601,6 +593,24 @@ public class GenericClient extends BaseClient implements IGenericClient {
}
/**
* Returns null if encoding can't be determined
*/
private static EncodingEnum determineRawEncoding(String theResourceBody) {
EncodingEnum encoding = null;
for (int i = 0; i < theResourceBody.length() && encoding == null; i++) {
switch (theResourceBody.charAt(i)) {
case '<':
encoding = EncodingEnum.XML;
break;
case '{':
encoding = EncodingEnum.JSON;
break;
}
}
return encoding;
}
private final class BundleResponseHandler implements IClientResponseHandler<Bundle> {
private Class<? extends IBaseResource> myType;
@ -621,6 +631,15 @@ public class GenericClient extends BaseClient implements IGenericClient {
}
}
private final class StringResponseHandler implements IClientResponseHandler<String> {
@Override
public String invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map<String, List<String>> theHeaders) throws IOException,
BaseServerResponseException {
return IOUtils.toString(theResponseReader);
}
}
private class CreateInternal extends BaseClientExecutable<ICreateTyped, MethodOutcome> implements ICreate, ICreateTyped, ICreateWithQuery, ICreateWithQueryTyped {
private CriterionList myCriterionList;
@ -1538,6 +1557,8 @@ public class GenericClient extends BaseClient implements IGenericClient {
private Bundle myBundle;
private List<IResource> myResources;
private IBaseBundle myBaseBundle;
private String myRawBundle;
private EncodingEnum myRawBundleEncoding;
public TransactionExecutable(Bundle theResources) {
myBundle = theResources;
@ -1551,6 +1572,14 @@ public class GenericClient extends BaseClient implements IGenericClient {
myBaseBundle = theBundle;
}
public TransactionExecutable(String theBundle) {
myRawBundle = theBundle;
myRawBundleEncoding = determineRawEncoding(myRawBundle);
if (myRawBundleEncoding == null) {
throw new IllegalArgumentException("Can not determine encoding of raw resource body");
}
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public T execute() {
@ -1562,7 +1591,20 @@ public class GenericClient extends BaseClient implements IGenericClient {
} else if (myBaseBundle != null) {
ResourceResponseHandler binding = new ResourceResponseHandler(myBaseBundle.getClass(),null);
BaseHttpClientInvocation invocation = TransactionMethodBinding.createTransactionInvocation(myBaseBundle, myContext);
return (T) invoke(params, binding, invocation);
return (T) invoke(params, binding, invocation);
} else if (myRawBundle != null) {
StringResponseHandler binding = new StringResponseHandler();
/*
* If the user has explicitly requested a given encoding, we may need to reencode the raw string
*/
if (getParamEncoding() != null) {
if (determineRawEncoding(myRawBundle) != getParamEncoding()) {
IResource parsed = parseResourceBody(myRawBundle);
myRawBundle = getParamEncoding().newParser(getFhirContext()).encodeResourceToString(parsed);
}
}
BaseHttpClientInvocation invocation = TransactionMethodBinding.createTransactionInvocation(myRawBundle, myContext);
return (T) invoke(params, binding, invocation);
} else {
BundleResponseHandler binding = new BundleResponseHandler(null);
BaseHttpClientInvocation invocation = TransactionMethodBinding.createTransactionInvocation(myBundle, myContext);
@ -1592,6 +1634,12 @@ public class GenericClient extends BaseClient implements IGenericClient {
return new TransactionExecutable<T>(theBundle);
}
@Override
public ITransactionTyped<String> withBundle(String theBundle) {
Validate.notBlank(theBundle, "theBundle must not be null");
return new TransactionExecutable<String>(theBundle);
}
}
private class UpdateInternal extends BaseClientExecutable<IUpdateExecutable, MethodOutcome> implements IUpdate, IUpdateTyped, IUpdateExecutable, IUpdateWithQuery, IUpdateWithQueryTyped {

View File

@ -72,6 +72,11 @@ public interface IRestfulClientFactory {
*/
HttpClient getHttpClient();
/**
* @deprecated Use {@link #getServerValidationMode()} instead
*/
ServerValidationModeEnum getServerValidationModeEnum();
/**
* Gets the server validation mode for any clients created from this factory. Server
* validation involves the client requesting the server's conformance statement
@ -79,8 +84,10 @@ public interface IRestfulClientFactory {
* <p>
* The default value for this setting is defined by {@link #DEFAULT_SERVER_VALIDATION_MODE}
* </p>
*
* @since 1.0
*/
ServerValidationModeEnum getServerValidationModeEnum();
ServerValidationModeEnum getServerValidationMode();
/**
* Gets the socket timeout, in milliseconds. This is the SO_TIMEOUT time, which is the amount of time that a
@ -158,6 +165,11 @@ public interface IRestfulClientFactory {
*/
void setProxyCredentials(String theUsername, String thePassword);
/**
* @deprecated Use {@link #setServerValidationMode(ServerValidationModeEnum)} instead. This method was incorrectly named.
*/
void setServerValidationModeEnum(ServerValidationModeEnum theServerValidationMode);
/**
* Sets the server validation mode for any clients created from this factory. Server
* validation involves the client requesting the server's conformance statement
@ -165,8 +177,10 @@ public interface IRestfulClientFactory {
* <p>
* The default value for this setting is defined by {@link #DEFAULT_SERVER_VALIDATION_MODE}
* </p>
*
* @since 1.0
*/
void setServerValidationModeEnum(ServerValidationModeEnum theServerValidationMode);
void setServerValidationMode(ServerValidationModeEnum theServerValidationMode);
/**
* Sets the socket timeout, in milliseconds. This is the SO_TIMEOUT time, which is the amount of time that a

View File

@ -135,7 +135,7 @@ public class RestfulClientFactory implements IRestfulClientFactory {
}
@Override
public ServerValidationModeEnum getServerValidationModeEnum() {
public ServerValidationModeEnum getServerValidationMode() {
return myServerValidationMode;
}
@ -256,7 +256,7 @@ public class RestfulClientFactory implements IRestfulClientFactory {
}
@Override
public void setServerValidationModeEnum(ServerValidationModeEnum theServerValidationMode) {
public void setServerValidationMode(ServerValidationModeEnum theServerValidationMode) {
Validate.notNull(theServerValidationMode, "theServerValidationMode may not be null");
myServerValidationMode = theServerValidationMode;
}
@ -304,4 +304,14 @@ public class RestfulClientFactory implements IRestfulClientFactory {
}
}
@Override
public ServerValidationModeEnum getServerValidationModeEnum() {
return getServerValidationMode();
}
@Override
public void setServerValidationModeEnum(ServerValidationModeEnum theServerValidationMode) {
setServerValidationMode(theServerValidationMode);
}
}

View File

@ -44,9 +44,9 @@ public interface ITransaction {
*/
<T extends IBaseBundle> ITransactionTyped<T> withBundle(T theBundleResource);
// *****
// TODO: add withString version
// If we add a withString version, make sure to auto-detect content type!
// *****
/**
* Use the given raw text (should be a Bundle resource) as the transaction input
*/
ITransactionTyped<String> withBundle(String theBundle);
}

View File

@ -37,6 +37,7 @@ import org.hl7.fhir.instance.model.IBaseResource;
import org.hl7.fhir.instance.model.api.IBaseBinary;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.TagList;
@ -48,6 +49,7 @@ import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.EncodingEnum;
import ca.uhn.fhir.rest.server.IVersionSpecificBundleFactory;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.validation.FhirValidator;
/**
* @author James Agnew
@ -271,7 +273,7 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
}
} else if (myContents != null) {
contents = myContents;
if (myContentsIsBundle) {
if (myContentsIsBundle && myContext.getVersion().getVersion().equals(FhirVersionEnum.DSTU1)) {
contentType = encoding.getBundleContentType();
} else {
contentType = encoding.getResourceContentType();

View File

@ -198,4 +198,8 @@ public class TransactionMethodBinding extends BaseResourceReturningMethodBinding
return new HttpPostClientInvocation(theContext, theResources, BundleTypeEnum.TRANSACTION);
}
public static BaseHttpClientInvocation createTransactionInvocation(String theRawBundle, FhirContext theContext) {
return new HttpPostClientInvocation(theContext, theRawBundle, true, "");
}
}

View File

@ -4,6 +4,7 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.List;
import org.apache.commons.io.IOUtils;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
@ -14,12 +15,9 @@ import org.springframework.context.support.ClassPathXmlApplicationContext;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
import ca.uhn.fhir.jpa.provider.JpaSystemProviderDstu1;
import ca.uhn.fhir.jpa.rp.dstu.ObservationResourceProvider;
import ca.uhn.fhir.jpa.rp.dstu.OrganizationResourceProvider;
import ca.uhn.fhir.jpa.rp.dstu.PatientResourceProvider;
import ca.uhn.fhir.jpa.provider.QuestionnaireResourceProvider;
import ca.uhn.fhir.jpa.testutil.RandomServerPortProvider;
import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.IResource;
@ -41,11 +39,9 @@ public class SystemProviderTest {
@Test
public void testTransactionFromBundle() throws Exception {
InputStream bundleRes = SystemProviderTest.class.getResourceAsStream("/test-server-seed-bundle.json");
Bundle bundle = FhirContext.forDstu1().newJsonParser().parseBundle(new InputStreamReader(bundleRes));
List<IResource> res = bundle.toListOfResources();
ourClient.transaction().withResources(res).execute();
InputStream bundleRes = SystemProviderTest.class.getResourceAsStream("/transaction_link_patient_eve.xml");
String bundle = IOUtils.toString(bundleRes);
String response = ourClient.transaction().withBundle(bundle).execute();
}
@ -59,28 +55,28 @@ public class SystemProviderTest {
@SuppressWarnings("unchecked")
@BeforeClass
public static void beforeClass() throws Exception {
ourAppCtx = new ClassPathXmlApplicationContext("fhir-jpabase-spring-test-config.xml", "hapi-fhir-server-resourceproviders-dstu1.xml");
ourAppCtx = new ClassPathXmlApplicationContext("fhir-jpabase-spring-test-config.xml", "hapi-fhir-server-resourceproviders-dstu2.xml");
IFhirResourceDao<Patient> patientDao = (IFhirResourceDao<Patient>) ourAppCtx.getBean("myPatientDaoDstu1", IFhirResourceDao.class);
IFhirResourceDao<Patient> patientDao = (IFhirResourceDao<Patient>) ourAppCtx.getBean("myPatientDaoDstu2", IFhirResourceDao.class);
PatientResourceProvider patientRp = new PatientResourceProvider();
patientRp.setDao(patientDao);
IFhirResourceDao<Questionnaire> questionnaireDao = (IFhirResourceDao<Questionnaire>) ourAppCtx.getBean("myQuestionnaireDaoDstu1", IFhirResourceDao.class);
IFhirResourceDao<Questionnaire> questionnaireDao = (IFhirResourceDao<Questionnaire>) ourAppCtx.getBean("myQuestionnaireDaoDstu2", IFhirResourceDao.class);
QuestionnaireResourceProvider questionnaireRp = new QuestionnaireResourceProvider();
questionnaireRp.setDao(questionnaireDao);
IFhirResourceDao<Observation> observationDao = (IFhirResourceDao<Observation>) ourAppCtx.getBean("myObservationDaoDstu1", IFhirResourceDao.class);
IFhirResourceDao<Observation> observationDao = (IFhirResourceDao<Observation>) ourAppCtx.getBean("myObservationDaoDstu2", IFhirResourceDao.class);
ObservationResourceProvider observationRp = new ObservationResourceProvider();
observationRp.setDao(observationDao);
IFhirResourceDao<Organization> organizationDao = (IFhirResourceDao<Organization>) ourAppCtx.getBean("myOrganizationDaoDstu1", IFhirResourceDao.class);
IFhirResourceDao<Organization> organizationDao = (IFhirResourceDao<Organization>) ourAppCtx.getBean("myOrganizationDaoDstu2", IFhirResourceDao.class);
OrganizationResourceProvider organizationRp = new OrganizationResourceProvider();
organizationRp.setDao(organizationDao);
RestfulServer restServer = new RestfulServer();
restServer.setResourceProviders(patientRp, questionnaireRp, observationRp, organizationRp);
JpaSystemProviderDstu1 systemProv = ourAppCtx.getBean(JpaSystemProviderDstu1.class, "mySystemProviderDstu1");
JpaSystemProviderDstu2 systemProv = ourAppCtx.getBean(JpaSystemProviderDstu2.class, "mySystemProviderDstu2");
restServer.setPlainProviders(systemProv);
int myPort = RandomServerPortProvider.findFreePort();
@ -95,10 +91,12 @@ public class SystemProviderTest {
servletHolder.setServlet(restServer);
proxyHandler.addServlet(servletHolder, "/fhir/context/*");
ourCtx = FhirContext.forDstu2();
restServer.setFhirContext(ourCtx);
ourServer.setHandler(proxyHandler);
ourServer.start();
ourCtx = restServer.getFhirContext();
ourCtx.getRestfulClientFactory().setSocketTimeout(600 * 1000);
ourClient = ourCtx.newRestfulGenericClient(serverBase);

View File

@ -1,690 +0,0 @@
{
"resourceType":"Bundle",
"entry":[
{
"deleted":null,
"title":"Patient http://uhnvesb01d.uhn.on.ca:25180/uhn-fhir-service-1.0/Patient/5556918",
"id":"Patient/5556918",
"link":[
{
"rel":"self",
"href":"Patient/5556918"
}
],
"published":"2014-05-29T10:49:32-04:00",
"content":{
"resourceType":"Patient",
"id":"http://uhnvesb01d.uhn.on.ca:25180/uhn-fhir-service-1.0/Patient/5556918",
"text":{
"status":"generated",
"div":"<div xmlns=\"http://www.w3.org/1999/xhtml\"><div class=\"hapiHeaderText\"> Donald null <b>DUCK </b></div><table class=\"hapiPropertyTable\"><tbody><tr><td>Identifier</td><td>7000135</td></tr><tr><td>Address</td><td><span>10 Duxon Street </span><br/><span>VICTORIA </span><span>BC </span><span>Can </span></td></tr><tr><td>Date of birth</td><td><span>01 June 1980</span></td></tr></tbody></table></div>"
},
"identifier":[
{
"use":"official",
"label":"University Health Network MRN 7000135",
"system":"urn:oid:2.16.840.1.113883.3.239.18.148",
"value":"7000135",
"assigner":{
"resource":"Organization/1.3.6.1.4.1.12201"
}
}
],
"name":[
{
"family":[
"Duck"
],
"given":[
"Donald"
]
}
],
"telecom":[
{
"system":"phone",
"use":"home"
},
{
"system":"phone",
"use":"work"
},
{
"system":"phone",
"use":"mobile"
},
{
"system":"email",
"use":"home"
}
],
"gender":{
"coding":[
{
"system":"http://hl7.org/fhir/v3/AdministrativeGender",
"code":"M"
}
]
},
"birthDate":"1980-06-01T00:00:00",
"address":[
{
"use":"home",
"line":[
"10 Duxon Street"
],
"city":"VICTORIA",
"state":"BC",
"zip":"V8N 1Y4",
"country":"Can"
}
],
"managingOrganization":{
"resource":"Organization/1.3.6.1.4.1.12201"
}
}
},
{
"deleted":null,
"title":"DiagnosticReport http://uhnvesb01d.uhn.on.ca:25180/uhn-fhir-service-1.0/DiagnosticReport/5978827",
"id":"DiagnosticReport/5978827",
"link":[
{
"rel":"self",
"href":"DiagnosticReport/5978827"
}
],
"published":"2014-05-29T10:49:33-04:00",
"content":{
"resourceType":"DiagnosticReport",
"id":"http://uhnvesb01d.uhn.on.ca:25180/uhn-fhir-service-1.0/DiagnosticReport/5978827",
"text":{
"status":"generated",
"div":"<div xmlns=\"http://www.w3.org/1999/xhtml\"><div class=\"hapiHeaderText\"> C&amp;S </div><table class=\"hapiPropertyTable\"><tbody><tr><td>Status</td><td>partial</td></tr><tr><td>Issued</td><td> 29 April 2014 17:21:56 </td></tr></tbody></table><table class=\"hapiTableOfValues\"><thead><tr><td>Name</td><td>Value</td><td>Interpretation</td><td>Reference Range</td><td>Status</td></tr></thead><tbody><tr class=\"hapiTableOfValuesRowEven\"><td> Collection Info </td><td> Spec #102758: 26 Sep 08 1117</td><td/><td/><td>preliminary</td></tr><tr class=\"hapiTableOfValuesRowOdd\"><td> Direct Stain </td><td> pus cells</td><td/><td/><td>preliminary</td></tr><tr class=\"hapiTableOfValuesRowEven\"><td> Header </td><td> To view Culture &amp; Sensitivity Results, select</td><td/><td/><td/></tr><tr class=\"hapiTableOfValuesRowOdd\"><td> Header </td><td> (Y) Report Query. Do NOT select number beside</td><td/><td/><td/></tr><tr class=\"hapiTableOfValuesRowEven\"><td> Header </td><td> Prelim or Final Result field, as there is</td><td/><td/><td/></tr><tr class=\"hapiTableOfValuesRowOdd\"><td> Header </td><td> potential for viewing an incomplete report.</td><td/><td/><td/></tr><tr class=\"hapiTableOfValuesRowEven\"><td> Organism </td><td> Haemophilus influenzae</td><td/><td/><td>final</td></tr><tr class=\"hapiTableOfValuesRowOdd\"><td> Qualifier </td><td> =>10 x E6 cfu/L SIGNIFICANT RESULT. Organisms cultured in quantities =>10 x E6 cfu/L are consistent with pneumonia. beta-lactamase positive result suggests resistance to ampicillin but generally susceptible to amoxicillin- clavulanic and cefuroxime.</td><td/><td/><td>final</td></tr><tr class=\"hapiTableOfValuesRowEven\"><td> Sensitivities </td><td> _Beta-lactamase Pos: </td><td/><td/><td>final</td></tr><tr class=\"hapiTableOfValuesRowOdd\"><td> Test Comment </td><td> =>10 x E6 cfu/L Commensal flora</td><td/><td/><td>final</td></tr></tbody></table></div>"
},
"contained":[
{
"resourceType":"Observation",
"id":"f816a276-cfad-4eca-a9fa-f1dff844a196",
"name":{
"coding":[
{
"system":"urn:oid:1.3.6.1.4.1.12201.102.6",
"code":"146151.1"
}
],
"text":"Collection Info"
},
"valueString":"Spec #102758: 26 Sep 08 1117",
"interpretation":{
"coding":[
{
"code":"N"
}
]
},
"issued":"2014-04-29T17:21:56",
"status":"preliminary"
},
{
"resourceType":"Observation",
"id":"23b55496-1c2a-4d5f-9c24-8ca5042f4027",
"name":{
"coding":[
{
"system":"urn:oid:1.3.6.1.4.1.12201.102.6",
"code":"GM.2"
}
],
"text":"Direct Stain"
},
"valueString":"pus cells",
"interpretation":{
"coding":[
{
"code":"N"
}
]
},
"issued":"2014-04-29T17:21:56",
"status":"preliminary"
},
{
"resourceType":"Observation",
"id":"74e6791a-d810-4545-8410-e9eca41e81d6",
"name":{
"coding":[
{
"system":"urn:oid:1.3.6.1.4.1.12201.102.6",
"code":"1H1.3"
}
],
"text":"Header"
},
"valueString":"To view Culture & Sensitivity Results, select",
"issued":"2014-04-29T17:21:56"
},
{
"resourceType":"Observation",
"id":"cd8c6a6c-7ef5-446f-b07b-47a21bfe28ee",
"name":{
"coding":[
{
"system":"urn:oid:1.3.6.1.4.1.12201.102.6",
"code":"1H2.4"
}
],
"text":"Header"
},
"valueString":"(Y) Report Query. Do NOT select number beside",
"issued":"2014-04-29T17:21:56"
},
{
"resourceType":"Observation",
"id":"4a3d453d-3a18-432f-8f1f-d7657c50dcd4",
"name":{
"coding":[
{
"system":"urn:oid:1.3.6.1.4.1.12201.102.6",
"code":"1H3.5"
}
],
"text":"Header"
},
"valueString":"Prelim or Final Result field, as there is",
"issued":"2014-04-29T17:21:56"
},
{
"resourceType":"Observation",
"id":"0dd6cff6-f9db-42cc-89c9-2cd6ba6fe5af",
"name":{
"coding":[
{
"system":"urn:oid:1.3.6.1.4.1.12201.102.6",
"code":"1H4.6"
}
],
"text":"Header"
},
"valueString":"potential for viewing an incomplete report.",
"issued":"2014-04-29T17:21:56"
},
{
"resourceType":"Observation",
"id":"6d6b0117-220f-4b9a-abf3-5faf772cfa61",
"name":{
"coding":[
{
"system":"urn:oid:1.3.6.1.4.1.12201.102.6",
"code":"F/O.4"
}
],
"text":"Organism"
},
"valueString":"Haemophilus influenzae",
"interpretation":{
"coding":[
{
"code":"A"
}
]
},
"issued":"2014-04-29T17:21:56",
"status":"final"
},
{
"resourceType":"Observation",
"id":"64068acf-57f4-42c8-b0e6-416247067b16",
"name":{
"coding":[
{
"system":"urn:oid:1.3.6.1.4.1.12201.102.6",
"code":"F/31266.5"
}
],
"text":"Qualifier"
},
"valueString":"=>10 x E6 cfu/L SIGNIFICANT RESULT. Organisms cultured in quantities =>10 x E6 cfu/L are consistent with pneumonia. beta-lactamase positive result suggests resistance to ampicillin but generally susceptible to amoxicillin- clavulanic and cefuroxime.",
"interpretation":{
"coding":[
{
"code":"A"
}
]
},
"issued":"2014-04-29T17:21:56",
"status":"final"
},
{
"resourceType":"Observation",
"id":"0f9d254f-3ad1-404b-9be9-20258b3c242f",
"name":{
"coding":[
{
"system":"urn:oid:1.3.6.1.4.1.12201.102.6",
"code":"F/31415.6"
}
],
"text":"Sensitivities"
},
"valueString":"_Beta-lactamase Pos: ",
"interpretation":{
"coding":[
{
"code":"A"
}
]
},
"issued":"2014-04-29T17:21:56",
"status":"final"
},
{
"resourceType":"Observation",
"id":"349bb02b-fbbe-4ce0-b190-3f545240dcc0",
"name":{
"coding":[
{
"system":"urn:oid:1.3.6.1.4.1.12201.102.6",
"code":"Q.3"
}
],
"text":"Test Comment"
},
"valueString":"=>10 x E6 cfu/L Commensal flora",
"interpretation":{
"coding":[
{
"code":"N"
}
]
},
"issued":"2014-04-29T17:21:56",
"status":"final"
},
{
"resourceType":"Observation",
"id":"f816a276-cfad-4eca-a9fa-f1dff844a196",
"name":{
"coding":[
{
"system":"urn:oid:1.3.6.1.4.1.12201.102.6",
"code":"146151.1"
}
],
"text":"Collection Info"
},
"valueString":"Spec #102758: 26 Sep 08 1117",
"interpretation":{
"coding":[
{
"code":"N"
}
]
},
"issued":"2014-04-29T17:21:56",
"status":"preliminary"
},
{
"resourceType":"Observation",
"id":"23b55496-1c2a-4d5f-9c24-8ca5042f4027",
"name":{
"coding":[
{
"system":"urn:oid:1.3.6.1.4.1.12201.102.6",
"code":"GM.2"
}
],
"text":"Direct Stain"
},
"valueString":"pus cells",
"interpretation":{
"coding":[
{
"code":"N"
}
]
},
"issued":"2014-04-29T17:21:56",
"status":"preliminary"
},
{
"resourceType":"Observation",
"id":"74e6791a-d810-4545-8410-e9eca41e81d6",
"name":{
"coding":[
{
"system":"urn:oid:1.3.6.1.4.1.12201.102.6",
"code":"1H1.3"
}
],
"text":"Header"
},
"valueString":"To view Culture & Sensitivity Results, select",
"issued":"2014-04-29T17:21:56"
},
{
"resourceType":"Observation",
"id":"cd8c6a6c-7ef5-446f-b07b-47a21bfe28ee",
"name":{
"coding":[
{
"system":"urn:oid:1.3.6.1.4.1.12201.102.6",
"code":"1H2.4"
}
],
"text":"Header"
},
"valueString":"(Y) Report Query. Do NOT select number beside",
"issued":"2014-04-29T17:21:56"
},
{
"resourceType":"Observation",
"id":"4a3d453d-3a18-432f-8f1f-d7657c50dcd4",
"name":{
"coding":[
{
"system":"urn:oid:1.3.6.1.4.1.12201.102.6",
"code":"1H3.5"
}
],
"text":"Header"
},
"valueString":"Prelim or Final Result field, as there is",
"issued":"2014-04-29T17:21:56"
},
{
"resourceType":"Observation",
"id":"0dd6cff6-f9db-42cc-89c9-2cd6ba6fe5af",
"name":{
"coding":[
{
"system":"urn:oid:1.3.6.1.4.1.12201.102.6",
"code":"1H4.6"
}
],
"text":"Header"
},
"valueString":"potential for viewing an incomplete report.",
"issued":"2014-04-29T17:21:56"
},
{
"resourceType":"Observation",
"id":"6d6b0117-220f-4b9a-abf3-5faf772cfa61",
"name":{
"coding":[
{
"system":"urn:oid:1.3.6.1.4.1.12201.102.6",
"code":"F/O.4"
}
],
"text":"Organism"
},
"valueString":"Haemophilus influenzae",
"interpretation":{
"coding":[
{
"code":"A"
}
]
},
"issued":"2014-04-29T17:21:56",
"status":"final"
},
{
"resourceType":"Observation",
"id":"64068acf-57f4-42c8-b0e6-416247067b16",
"name":{
"coding":[
{
"system":"urn:oid:1.3.6.1.4.1.12201.102.6",
"code":"F/31266.5"
}
],
"text":"Qualifier"
},
"valueString":"=>10 x E6 cfu/L SIGNIFICANT RESULT. Organisms cultured in quantities =>10 x E6 cfu/L are consistent with pneumonia. beta-lactamase positive result suggests resistance to ampicillin but generally susceptible to amoxicillin- clavulanic and cefuroxime.",
"interpretation":{
"coding":[
{
"code":"A"
}
]
},
"issued":"2014-04-29T17:21:56",
"status":"final"
},
{
"resourceType":"Observation",
"id":"0f9d254f-3ad1-404b-9be9-20258b3c242f",
"name":{
"coding":[
{
"system":"urn:oid:1.3.6.1.4.1.12201.102.6",
"code":"F/31415.6"
}
],
"text":"Sensitivities"
},
"valueString":"_Beta-lactamase Pos: ",
"interpretation":{
"coding":[
{
"code":"A"
}
]
},
"issued":"2014-04-29T17:21:56",
"status":"final"
},
{
"resourceType":"Observation",
"id":"349bb02b-fbbe-4ce0-b190-3f545240dcc0",
"name":{
"coding":[
{
"system":"urn:oid:1.3.6.1.4.1.12201.102.6",
"code":"Q.3"
}
],
"text":"Test Comment"
},
"valueString":"=>10 x E6 cfu/L Commensal flora",
"interpretation":{
"coding":[
{
"code":"N"
}
]
},
"issued":"2014-04-29T17:21:56",
"status":"final"
}
],
"name":{
"coding":[
{
"system":"urn:oid:1.3.6.1.4.1.12201.102.5",
"code":"4140"
}
],
"text":"C&S"
},
"status":"partial",
"issued":"2014-04-29T17:21:56",
"subject":{
"resource":"Patient/5556918"
},
"identifier":{
"value":"2363922"
},
"diagnosticDateTime":"2014-04-14T00:00:00-04:00",
"result":[
{
"resource":"#f816a276-cfad-4eca-a9fa-f1dff844a196"
},
{
"resource":"#23b55496-1c2a-4d5f-9c24-8ca5042f4027"
},
{
"resource":"#74e6791a-d810-4545-8410-e9eca41e81d6"
},
{
"resource":"#cd8c6a6c-7ef5-446f-b07b-47a21bfe28ee"
},
{
"resource":"#4a3d453d-3a18-432f-8f1f-d7657c50dcd4"
},
{
"resource":"#0dd6cff6-f9db-42cc-89c9-2cd6ba6fe5af"
},
{
"resource":"#6d6b0117-220f-4b9a-abf3-5faf772cfa61"
},
{
"resource":"#64068acf-57f4-42c8-b0e6-416247067b16"
},
{
"resource":"#0f9d254f-3ad1-404b-9be9-20258b3c242f"
},
{
"resource":"#349bb02b-fbbe-4ce0-b190-3f545240dcc0"
}
]
}
},
{
"deleted":null,
"title":"Organization http://uhnvesb01d.uhn.on.ca:25180/uhn-fhir-service-1.0/Organization/1.3.6.1.4.1.12201",
"id":"Organization/1.3.6.1.4.1.12201",
"link":[
{
"rel":"self",
"href":"Organization/1.3.6.1.4.1.12201"
}
],
"published":"2014-05-29T10:49:32-04:00",
"content":{
"resourceType":"Organization",
"id":"http://uhnvesb01d.uhn.on.ca:25180/uhn-fhir-service-1.0/Organization/1.3.6.1.4.1.12201",
"extension":[
{
"url":"http://fhir.connectinggta.ca/Profile/organization#providerIdPool",
"valueUri":"1.3.6.1.4.1.12201.1"
}
],
"text":{
"status":"empty",
"div":"<div xmlns=\"http://www.w3.org/1999/xhtml\">No narrative template available for resource profile: http://fhir.connectinggta.ca/Profile/organization</div>"
},
"contained":[
{
"resourceType":"Location",
"id":"1.3.6.1.4.1.12201.100.1",
"identifier":{
"system":"urn:cgta:facility_ids",
"value":"1.3.6.1.4.1.12201.100.1"
},
"name":"Toronto General Hospital"
},
{
"resourceType":"Location",
"id":"1.3.6.1.4.1.12201.100.2",
"identifier":{
"system":"urn:cgta:facility_ids",
"value":"1.3.6.1.4.1.12201.100.2"
},
"name":"Toronto Western Hospital"
},
{
"resourceType":"Location",
"id":"1.3.6.1.4.1.12201.100.3",
"identifier":{
"system":"urn:cgta:facility_ids",
"value":"1.3.6.1.4.1.12201.100.3"
},
"name":"Princess Margaret Hospital"
},
{
"resourceType":"Location",
"id":"1.3.6.1.4.1.12201.100.4",
"identifier":{
"system":"urn:cgta:facility_ids",
"value":"1.3.6.1.4.1.12201.100.4"
},
"name":"Toronto Rehab Institute"
},
{
"resourceType":"Location",
"id":"1.3.6.1.4.1.12201.100.1",
"identifier":{
"system":"urn:cgta:facility_ids",
"value":"1.3.6.1.4.1.12201.100.1"
},
"name":"Toronto General Hospital"
},
{
"resourceType":"Location",
"id":"1.3.6.1.4.1.12201.100.2",
"identifier":{
"system":"urn:cgta:facility_ids",
"value":"1.3.6.1.4.1.12201.100.2"
},
"name":"Toronto Western Hospital"
},
{
"resourceType":"Location",
"id":"1.3.6.1.4.1.12201.100.3",
"identifier":{
"system":"urn:cgta:facility_ids",
"value":"1.3.6.1.4.1.12201.100.3"
},
"name":"Princess Margaret Hospital"
},
{
"resourceType":"Location",
"id":"1.3.6.1.4.1.12201.100.4",
"identifier":{
"system":"urn:cgta:facility_ids",
"value":"1.3.6.1.4.1.12201.100.4"
},
"name":"Toronto Rehab Institute"
}
],
"name":"University Health Network",
"type":{
"coding":[
{
"code":"HOSPITAL"
}
]
},
"address":[
{
"line":[
"R. Fraser Elliott Building, 1st Floor",
"190 Elizabeth St."
],
"city":"Toronto",
"state":"ON",
"zip":"M5G 2C4"
}
],
"location":[
{
"resource":"#1.3.6.1.4.1.12201.100.1"
},
{
"resource":"#1.3.6.1.4.1.12201.100.2"
},
{
"resource":"#1.3.6.1.4.1.12201.100.3"
},
{
"resource":"#1.3.6.1.4.1.12201.100.4"
}
]
}
}
]
}

View File

@ -0,0 +1,103 @@
<Bundle xmlns="http://hl7.org/fhir">
<id value="a130877d-a636-4993-97e6-0eeb7734e5"/>
<type value="transaction"/>
<entry>
<resource>
<Patient>
<!-- PID|||555-44-4444||EVERYWOMAN^EVE^E^^^^L|JONES|19620320|F|||153 FERNWOOD DR.^
^STATESVILLE^OH^35292||(206)3345232|(206)752-121||||AC555444444||67-A4335^OH^20030520 -->
<id value="555-44-4444"/>
<extension url="http://ihe.net/ITI-78/Profile/pdqm#mothersMaidenName">
<valueHumanName>
<family value="Jones"/>
</valueHumanName>
</extension>
<identifier>
<use value="official"/>
<system value="http://ghh.org/patient"/>
<value value="555-44-4444"/>
</identifier>
<identifier>
<use value="official"/>
<system value="http://www.ohio.gov/dmv/driverslicence"/>
<value value="67-A4335"/>
<period>
<end value="2003-05-20"/>
</period>
</identifier>
<name>
<use value="official"/>
<family value="Everywoman"/>
<given value="Eve E."/>
</name>
<telecom>
<system value="phone"/>
<value value="(206)3345232"/>
<use value="home"/>
</telecom>
<telecom>
<system value="phone"/>
<value value="(206)752-121"/>
<use value="work"/>
</telecom>
<gender value="female"/>
<birthDate value="1962-03-20"/>
<address>
<line value="153 Fernwood Dr."/>
<city value="Statesville"/>
<state value="OH"/>
<postalCode value="35292"/>
</address>
<managingOrganization>
<reference value="Organization/GHH"/>
<display value="Good Health Hospital"/>
</managingOrganization>
<link>
<other>
<reference value="Patient/temp6789"/>
</other>
<type value="seealso"/>
</link>
<active value="true"/>
</Patient>
</resource>
<transaction>
<method code="PUT"/>
<url value="Patient/555-44-4444"/>
</transaction>
</entry>
<entry>
<resource>
<Patient>
<!-- Jane Doe registered in the emergency department -->
<id value="temp6789"/>
<identifier>
<use value="temp"/>
<system value="http://ghh.org/patient"/>
<value value="temp6789"/>
</identifier>
<name>
<use value="temp"/>
<family value="Doe 6789"/>
<given value="Jane"/>
</name>
<gender value="female"/>
<managingOrganization>
<reference value="Organization/GHH"/>
<display value="Good Health Hospital"/>
</managingOrganization>
<link>
<other>
<reference value="Patient/555-44-4444"/>
</other>
<type value="replace"/>
</link>
<active value="true"/>
</Patient>
</resource>
<transaction>
<method code="PUT"/>
<url value="Patient/temp6789"/>
</transaction>
</entry>
</Bundle>

View File

@ -77,7 +77,7 @@ public class ClientServerValidationTestDstu2 {
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
myCtx.getRestfulClientFactory().setServerValidationModeEnum(ServerValidationModeEnum.ONCE);
myCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.ONCE);
IGenericClient client = myCtx.newRestfulGenericClient("http://foo");
// don't load the conformance until the first time the client is actually used
@ -115,7 +115,7 @@ public class ClientServerValidationTestDstu2 {
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
myCtx.getRestfulClientFactory().setServerValidationModeEnum(ServerValidationModeEnum.ONCE);
myCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.ONCE);
IGenericClient client = myCtx.newRestfulGenericClient("http://foo");
// don't load the conformance until the first time the client is actually used
@ -143,7 +143,7 @@ public class ClientServerValidationTestDstu2 {
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
myCtx.getRestfulClientFactory().setServerValidationModeEnum(ServerValidationModeEnum.ONCE);
myCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.ONCE);
try {
myCtx.newRestfulGenericClient("http://foo").read(new UriDt("http://foo/Patient/123"));
fail();
@ -173,19 +173,27 @@ public class ClientServerValidationTestDstu2 {
myFirstResponse = false;
return new ReaderInputStream(new StringReader(confResource), Charset.forName("UTF-8"));
} else {
return new ReaderInputStream(new StringReader(myCtx.newXmlParser().encodeResourceToString(new Patient())), Charset.forName("UTF-8"));
Patient resource = new Patient();
resource.addName().addFamily().setValue("FAM");
return new ReaderInputStream(new StringReader(myCtx.newXmlParser().encodeResourceToString(resource)), Charset.forName("UTF-8"));
}
}
});
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
myCtx.getRestfulClientFactory().setServerValidationModeEnum(ServerValidationModeEnum.ONCE);
myCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.ONCE);
IGenericClient client = myCtx.newRestfulGenericClient("http://foo");
client.registerInterceptor(new BasicAuthInterceptor("USER", "PASS"));
client.read(new UriDt("http://foo/Patient/123"));
Patient pt = (Patient) client.read(new UriDt("http://foo/Patient/123"));
assertEquals("FAM", pt.getNameFirstRep().getFamilyAsSingleString());
Header auth = capt.getValue().getFirstHeader("Authorization");
assertEquals(2, capt.getAllValues().size());
Header auth = capt.getAllValues().get(0).getFirstHeader("Authorization");
assertNotNull(auth);
assertEquals("Basic VVNFUjpQQVNT", auth.getValue());
auth = capt.getAllValues().get(1).getFirstHeader("Authorization");
assertNotNull(auth);
assertEquals("Basic VVNFUjpQQVNT", auth.getValue());
}

View File

@ -8,6 +8,7 @@ import static org.mockito.Mockito.when;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.StringReader;
import java.nio.charset.Charset;
import java.util.ArrayList;
@ -34,6 +35,7 @@ import org.mockito.stubbing.Answer;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.dstu2.resource.Observation;
import ca.uhn.fhir.model.dstu2.resource.Parameters;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.primitive.IdDt;
@ -614,6 +616,64 @@ public class GenericClientTestDstu2 {
// assertEquals("PATIENT2", p2.getName().get(0).getFamily().get(0).getValue());
}
@Test
public void testTransactionWithString() throws Exception {
ca.uhn.fhir.model.dstu2.resource.Bundle req = new ca.uhn.fhir.model.dstu2.resource.Bundle();
req.addEntry().setResource(new Patient());
req.addEntry().setResource(new Observation());
String reqStringJson = ourCtx.newJsonParser().encodeResourceToString(req);
String reqStringXml = ourCtx.newXmlParser().encodeResourceToString(req);
ca.uhn.fhir.model.dstu2.resource.Bundle resp = new ca.uhn.fhir.model.dstu2.resource.Bundle();
resp.addEntry().getTransactionResponse().setLocation("Patient/1/_history/1");
resp.addEntry().getTransactionResponse().setLocation("Patient/2/_history/2");
final String respStringJson = ourCtx.newJsonParser().encodeResourceToString(resp);
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_JSON + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenAnswer(new Answer<InputStream>() {
@Override
public InputStream answer(InvocationOnMock theInvocation) throws Throwable {
return new ReaderInputStream(new StringReader(respStringJson), Charset.forName("UTF-8"));
}});
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
//@formatter:off
String response = client.transaction()
.withBundle(reqStringJson)
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/", capt.getValue().getURI().toString());
assertEquals(respStringJson, response);
String requestString = IOUtils.toString(((HttpEntityEnclosingRequest) capt.getValue()).getEntity().getContent());
IOUtils.closeQuietly(((HttpEntityEnclosingRequest) capt.getValue()).getEntity().getContent());
assertEquals(reqStringJson, requestString);
assertEquals("application/json+fhir; charset=UTF-8", capt.getValue().getFirstHeader("Content-Type").getValue());
//@formatter:off
response = client.transaction()
.withBundle(reqStringJson)
.encodedXml()
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/?_format=xml", capt.getValue().getURI().toString());
assertEquals(respStringJson, response);
requestString = IOUtils.toString(((HttpEntityEnclosingRequest) capt.getValue()).getEntity().getContent());
IOUtils.closeQuietly(((HttpEntityEnclosingRequest) capt.getValue()).getEntity().getContent());
assertEquals(reqStringXml, requestString);
assertEquals("application/xml+fhir; charset=UTF-8", capt.getValue().getFirstHeader("Content-Type").getValue());
}
@Test
public void testTransactionWithTransactionResource() throws Exception {

View File

@ -155,6 +155,10 @@
populated in a resource ID when the resource is parsed. Thanks to
Nick Peterson for reporting, and for providing a test case!
</action>
<action type="add">
Allow fluent/generic client users to execute a transaction using a raw string (containing a bundle resource)
as input instead of a Bundle resource class instance.
</action>
</release>
<release version="0.9" date="2015-Mar-14">
<action type="add">