diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/Bundle.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/Bundle.java index 28e9415c8be..8e70a3666ed 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/Bundle.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/Bundle.java @@ -117,56 +117,63 @@ public class Bundle extends BaseBundle /* implements IElement */{ entry.getTitle().setValue(def.getName() + " " + StringUtils.defaultString(theResource.getId().getValue(), "(no ID)")); } - if (theResource.getId() != null && StringUtils.isNotBlank(theResource.getId().getValue())) { + if (theResource.getId() != null) { + if (theResource.getId().isAbsolute()) { + + entry.getLinkSelf().setValue(theResource.getId().getValue()); + entry.getId().setValue(theResource.getId().toVersionless().getValue()); + + } else if (StringUtils.isNotBlank(theResource.getId().getValue())) { - StringBuilder b = new StringBuilder(); - b.append(theServerBase); - if (b.length() > 0 && b.charAt(b.length() - 1) != '/') { + StringBuilder b = new StringBuilder(); + b.append(theServerBase); + if (b.length() > 0 && b.charAt(b.length() - 1) != '/') { + b.append('/'); + } + b.append(def.getName()); b.append('/'); - } - b.append(def.getName()); - b.append('/'); - String resId = theResource.getId().getIdPart(); - b.append(resId); + String resId = theResource.getId().getIdPart(); + b.append(resId); - entry.getId().setValue(b.toString()); + entry.getId().setValue(b.toString()); - if (isNotBlank(theResource.getId().getVersionIdPart())) { - b.append('/'); - b.append(Constants.PARAM_HISTORY); - b.append('/'); - b.append(theResource.getId().getVersionIdPart()); - } else { - IdDt versionId = (IdDt) ResourceMetadataKeyEnum.VERSION_ID.get(theResource); - if (versionId != null) { + if (isNotBlank(theResource.getId().getVersionIdPart())) { b.append('/'); b.append(Constants.PARAM_HISTORY); b.append('/'); - b.append(versionId.getValue()); + b.append(theResource.getId().getVersionIdPart()); + } else { + IdDt versionId = (IdDt) ResourceMetadataKeyEnum.VERSION_ID.get(theResource); + if (versionId != null) { + b.append('/'); + b.append(Constants.PARAM_HISTORY); + b.append('/'); + b.append(versionId.getValue()); + } } - } - String qualifiedId = b.toString(); - entry.getLinkSelf().setValue(qualifiedId); + String qualifiedId = b.toString(); + entry.getLinkSelf().setValue(qualifiedId); - // String resourceType = theContext.getResourceDefinition(theResource).getName(); + // String resourceType = theContext.getResourceDefinition(theResource).getName(); - String linkSearch = ResourceMetadataKeyEnum.LINK_SEARCH.get(theResource); - if (isNotBlank(linkSearch)) { - if (!UrlUtil.isAbsolute(linkSearch)) { - linkSearch = (theServerBase + "/" + linkSearch); + String linkSearch = ResourceMetadataKeyEnum.LINK_SEARCH.get(theResource); + if (isNotBlank(linkSearch)) { + if (!UrlUtil.isAbsolute(linkSearch)) { + linkSearch = (theServerBase + "/" + linkSearch); + } + entry.getLinkSearch().setValue(linkSearch); } - entry.getLinkSearch().setValue(linkSearch); - } - String linkAlternate = ResourceMetadataKeyEnum.LINK_ALTERNATE.get(theResource); - if (isNotBlank(linkAlternate)) { - if (!UrlUtil.isAbsolute(linkAlternate)) { - linkSearch = (theServerBase + "/" + linkAlternate); + String linkAlternate = ResourceMetadataKeyEnum.LINK_ALTERNATE.get(theResource); + if (isNotBlank(linkAlternate)) { + if (!UrlUtil.isAbsolute(linkAlternate)) { + linkSearch = (theServerBase + "/" + linkAlternate); + } + entry.getLinkAlternate().setValue(linkSearch); } - entry.getLinkAlternate().setValue(linkSearch); - } + } } InstantDt published = ResourceMetadataKeyEnum.PUBLISHED.get(theResource); diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/primitive/DateDt.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/primitive/DateDt.java index 82371ec8064..6c6e1801e03 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/primitive/DateDt.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/primitive/DateDt.java @@ -47,6 +47,7 @@ public class DateDt extends BaseDateTimeDt { @SimpleSetter(suffix="WithDayPrecision") public DateDt(@SimpleSetter.Parameter(name = "theDate") Date theDate) { setValue(theDate); + setPrecision(DEFAULT_PRECISION); } /** diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/GenericClient.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/GenericClient.java index 8c1c97e9fe0..10f8fbf96aa 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/GenericClient.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/GenericClient.java @@ -511,6 +511,10 @@ public class GenericClient extends BaseClient implements IGenericClient { return resp; } + protected EncodingEnum getParamEncoding() { + return myParamEncoding; + } + protected IResource parseResourceBody(String theResourceBody) { EncodingEnum encoding = null; for (int i = 0; i < theResourceBody.length() && encoding == null; i++) { @@ -571,6 +575,11 @@ public class GenericClient extends BaseClient implements IGenericClient { } myId = getPreferredId(myResource, myId); + // If an explicit encoding is chosen, we will re-serialize to ensure the right encoding + if (getParamEncoding() != null) { + myResourceBody = null; + } + BaseHttpClientInvocation invocation = MethodUtil.createCreateInvocation(myResource, myResourceBody, myId, myContext); RuntimeResourceDefinition def = myContext.getResourceDefinition(myResource); @@ -1102,6 +1111,11 @@ public class GenericClient extends BaseClient implements IGenericClient { throw new InvalidRequestException("No ID supplied for resource to update, can not invoke server"); } + // If an explicit encoding is chosen, we will re-serialize to ensure the right encoding + if (getParamEncoding() != null) { + myResourceBody = null; + } + BaseHttpClientInvocation invocation = MethodUtil.createUpdateInvocation(myResource, myResourceBody, myId, myContext); RuntimeResourceDefinition def = myContext.getResourceDefinition(myResource); diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/gclient/ITransaction.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/gclient/ITransaction.java index 2a5431cee3c..98c24628977 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/gclient/ITransaction.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/gclient/ITransaction.java @@ -31,4 +31,9 @@ public interface ITransaction { ITransactionTyped withBundle(Bundle theResources); + // ***** + // TODO: add withString version + // If we add a withString version, make sure to auto-detect content type! + // ***** + } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseHttpClientInvocationWithContents.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseHttpClientInvocationWithContents.java index 859c0d5d89e..ed441bca585 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseHttpClientInvocationWithContents.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseHttpClientInvocationWithContents.java @@ -44,6 +44,7 @@ import ca.uhn.fhir.model.dstu.resource.Binary; import ca.uhn.fhir.parser.DataFormatException; import ca.uhn.fhir.parser.IParser; import ca.uhn.fhir.rest.client.BaseHttpClientInvocation; +import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.server.EncodingEnum; import ca.uhn.fhir.rest.server.RestfulServer; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; @@ -165,6 +166,10 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca EncodingEnum encoding = null; encoding = theEncoding; + if (myContents != null) { + encoding = MethodUtil.detectEncoding(myContents); + } + if (encoding == EncodingEnum.JSON) { parser = myContext.newJsonParser(); } else { @@ -174,6 +179,7 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca AbstractHttpEntity entity; if (myParams != null) { + contentType= null; List parameters = new ArrayList(); for (Entry> nextParam : myParams.entrySet()) { List value = nextParam.getValue(); @@ -215,7 +221,9 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca HttpRequestBase retVal = createRequest(url, entity); super.addHeadersToRequest(retVal); - // retVal.addHeader(Constants.HEADER_CONTENT_TYPE, con); + if (contentType != null) { + retVal.addHeader(Constants.HEADER_CONTENT_TYPE, contentType); + } return retVal; } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/MethodUtil.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/MethodUtil.java index f665be603c2..fcb8c4e7207 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/MethodUtil.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/MethodUtil.java @@ -115,7 +115,8 @@ public class MethodUtil { } addTagsToPostOrPut(theResource, retVal); - +// addContentTypeHeaderBasedOnDetectedType(retVal, theResourceBody); + return retVal; } @@ -260,9 +261,23 @@ public class MethodUtil { } addTagsToPostOrPut(theResource, retVal); +// addContentTypeHeaderBasedOnDetectedType(retVal, theResourceBody); + return retVal; } + public static EncodingEnum detectEncoding(String theBody) { + for (int i = 0; i < theBody.length(); i++) { + switch (theBody.charAt(i)) { + case '<': + return EncodingEnum.XML; + case '{': + return EncodingEnum.JSON; + } + } + return EncodingEnum.XML; + } + public static HttpGetClientInvocation createConformanceInvocation() { return new HttpGetClientInvocation("metadata"); } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseFhirDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseFhirDao.java index 76d3321036e..a40715f617c 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseFhirDao.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseFhirDao.java @@ -312,14 +312,28 @@ public abstract class BaseFhirDao implements IDao { continue; } - String nextPath = nextSpDef.getPath(); + String nextPathsUnsplit = nextSpDef.getPath(); + if (isBlank(nextPathsUnsplit)) { + continue; + } boolean multiType = false; - if (nextPath.endsWith("[x]")) { + if (nextPathsUnsplit.endsWith("[x]")) { multiType = true; } - - List values = t.getValues(theResource, nextPath); + + List values = new ArrayList(); + + String[] nextPathsSplit = nextPathsUnsplit.split("\\|"); + for (String nextPath : nextPathsSplit) { + String nextPathTrimmed = nextPath.trim(); + try { + values.addAll(t.getValues(theResource, nextPathTrimmed)); + } catch (Exception e) { + ourLog.warn("Failed to index values from path[{}] in resource type[{}]: ", nextPathTrimmed, def.getName(), e.toString()); + } + } + for (Object nextObject : values) { if (nextObject == null) { continue; @@ -338,7 +352,7 @@ public abstract class BaseFhirDao implements IDao { String typeString = nextValue.getReference().getResourceType(); if (isBlank(typeString)) { - throw new InvalidRequestException("Invalid resource reference found at path[" + nextPath + "] - Does not contain resource type - " + nextValue.getReference().getValue()); + throw new InvalidRequestException("Invalid resource reference found at path[" + nextPathsUnsplit + "] - Does not contain resource type - " + nextValue.getReference().getValue()); } Class type = getContext().getResourceDefinition(typeString).getImplementingClass(); String id = nextValue.getReference().getIdPart(); @@ -355,14 +369,14 @@ public abstract class BaseFhirDao implements IDao { valueOf = translateForcedIdToPid(nextValue.getReference()); } catch (Exception e) { String resName = getContext().getResourceDefinition(type).getName(); - throw new InvalidRequestException("Resource " + resName + "/" + id + " not found, specified in path: " + nextPath + " (this is an invalid ID, must be numeric on this server)"); + throw new InvalidRequestException("Resource " + resName + "/" + id + " not found, specified in path: " + nextPathsUnsplit + " (this is an invalid ID, must be numeric on this server)"); } ResourceTable target = myEntityManager.find(ResourceTable.class, valueOf); if (target == null) { String resName = getContext().getResourceDefinition(type).getName(); - throw new InvalidRequestException("Resource " + resName + "/" + id + " not found, specified in path: " + nextPath); + throw new InvalidRequestException("Resource " + resName + "/" + id + " not found, specified in path: " + nextPathsUnsplit); } - nextEntity = new ResourceLink(nextPath, theEntity, target); + nextEntity = new ResourceLink(nextPathsUnsplit, theEntity, target); } else { if (!multiType) { throw new ConfigurationException("Search param " + nextSpDef.getName() + " is of unexpected datatype: " + nextObject.getClass()); @@ -392,6 +406,9 @@ public abstract class BaseFhirDao implements IDao { } String nextPath = nextSpDef.getPath(); + if (isBlank(nextPath)) { + continue; + } boolean multiType = false; if (nextPath.endsWith("[x]")) { @@ -447,6 +464,10 @@ public abstract class BaseFhirDao implements IDao { } String nextPath = nextSpDef.getPath(); + if (isBlank(nextPath)) { + continue; + } + List values = t.getValues(theResource, nextPath); for (Object nextObject : values) { if (nextObject == null || ((IDatatype) nextObject).isEmpty()) { @@ -526,6 +547,10 @@ public abstract class BaseFhirDao implements IDao { } String nextPath = nextSpDef.getPath(); + if (isBlank(nextPath)) { + continue; + } + List values = t.getValues(theResource, nextPath); for (Object nextObject : values) { if (nextObject == null || ((IDatatype) nextObject).isEmpty()) { @@ -572,12 +597,13 @@ public abstract class BaseFhirDao implements IDao { if (nextSpDef.getParamType() != SearchParamTypeEnum.STRING) { continue; } - if (nextSpDef.getPath().isEmpty()) { - continue; // TODO: implement phoenetic, and any others that have - // no path - } String nextPath = nextSpDef.getPath(); + if (isBlank(nextPath)) { + // TODO: implement phoenetic, and any others that have no path + continue; + } + List values = t.getValues(theResource, nextPath); for (Object nextObject : values) { if (nextObject == null || ((IDatatype) nextObject).isEmpty()) { @@ -663,9 +689,9 @@ public abstract class BaseFhirDao implements IDao { } String nextPath = nextSpDef.getPath(); - if (nextPath.isEmpty()) { + if (isBlank(nextPath)) { continue; - } + } boolean multiType = false; if (nextPath.endsWith("[x]")) { diff --git a/hapi-fhir-jpaserver-test/pom.xml b/hapi-fhir-jpaserver-test/pom.xml index 2450610c9d1..b030f9f9c57 100644 --- a/hapi-fhir-jpaserver-test/pom.xml +++ b/hapi-fhir-jpaserver-test/pom.xml @@ -138,8 +138,12 @@ ca.uhn.test.jpasrv device + documentmanifest + documentreference encounter + diagnosticorder diagnosticreport + imagingstudy location observation organization diff --git a/hapi-fhir-jpaserver-test/src/main/resources/fhir-spring-test-config.xml b/hapi-fhir-jpaserver-test/src/main/resources/fhir-spring-test-config.xml index 8f201345e00..c7b8c264c93 100644 --- a/hapi-fhir-jpaserver-test/src/main/resources/fhir-spring-test-config.xml +++ b/hapi-fhir-jpaserver-test/src/main/resources/fhir-spring-test-config.xml @@ -24,6 +24,9 @@ + + + @@ -43,6 +46,17 @@ + + + + + + + + + + + diff --git a/hapi-fhir-jpaserver-test/src/test/java/ca/uhn/fhir/jpa/test/CompleteResourceProviderTest.java b/hapi-fhir-jpaserver-test/src/test/java/ca/uhn/fhir/jpa/test/CompleteResourceProviderTest.java index d72f7fdb724..2667a223966 100644 --- a/hapi-fhir-jpaserver-test/src/test/java/ca/uhn/fhir/jpa/test/CompleteResourceProviderTest.java +++ b/hapi-fhir-jpaserver-test/src/test/java/ca/uhn/fhir/jpa/test/CompleteResourceProviderTest.java @@ -1,10 +1,14 @@ package ca.uhn.fhir.jpa.test; -import static org.hamcrest.Matchers.*; -import static org.junit.Assert.*; +import static org.hamcrest.Matchers.containsString; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; import java.util.Date; +import org.apache.commons.io.IOUtils; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; @@ -22,7 +26,11 @@ import ca.uhn.fhir.model.api.Bundle; import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.dstu.composite.PeriodDt; import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt; +import ca.uhn.fhir.model.dstu.resource.DiagnosticOrder; +import ca.uhn.fhir.model.dstu.resource.DocumentManifest; +import ca.uhn.fhir.model.dstu.resource.DocumentReference; import ca.uhn.fhir.model.dstu.resource.Encounter; +import ca.uhn.fhir.model.dstu.resource.ImagingStudy; import ca.uhn.fhir.model.dstu.resource.Location; import ca.uhn.fhir.model.dstu.resource.Observation; import ca.uhn.fhir.model.dstu.resource.Organization; @@ -41,7 +49,11 @@ import ca.uhn.fhir.rest.gclient.TokenClientParam; import ca.uhn.fhir.rest.server.RestfulServer; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException; +import ca.uhn.test.jpasrv.DiagnosticOrderResourceProvider; +import ca.uhn.test.jpasrv.DocumentManifestResourceProvider; +import ca.uhn.test.jpasrv.DocumentReferenceResourceProvider; import ca.uhn.test.jpasrv.EncounterResourceProvider; +import ca.uhn.test.jpasrv.ImagingStudyResourceProvider; import ca.uhn.test.jpasrv.LocationResourceProvider; import ca.uhn.test.jpasrv.ObservationResourceProvider; import ca.uhn.test.jpasrv.OrganizationResourceProvider; @@ -49,58 +61,74 @@ import ca.uhn.test.jpasrv.PatientResourceProvider; public class CompleteResourceProviderTest { - private static IFhirResourceDao observationDao; private static ClassPathXmlApplicationContext ourAppCtx; - private static IGenericClient ourClient; private static FhirContext ourCtx; private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(CompleteResourceProviderTest.class); + private static IFhirResourceDao ourObservationDao; + private static IFhirResourceDao ourPatientDao; + private static IFhirResourceDao ourQuestionnaireDao; + private static IFhirResourceDao ourImagingStudyDao; private static Server ourServer; - private static IFhirResourceDao patientDao; // private static JpaConformanceProvider ourConfProvider; - // @Test - // public void test01UploadTestResources() throws Exception { - // - // IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:8888/fhir/context"); - // - // File[] files = new File("src/test/resources/resources").listFiles(new PatternFilenameFilter(".*patient.*")); - // for (File file : files) { - // ourLog.info("Uploading: {}", file); - // Patient patient = ourCtx.newXmlParser().parseResource(Patient.class, new FileReader(file)); - // client.create(patient); - // } - // - // files = new File("src/test/resources/resources").listFiles(new PatternFilenameFilter(".*questionnaire.*")); - // for (File file : files) { - // ourLog.info("Uploading: {}", file); - // Questionnaire patient = ourCtx.newXmlParser().parseResource(Questionnaire.class, new FileReader(file)); - // client.create(patient); - // } - // - // } - - private static IFhirResourceDao questionnaireDao; - + /** + * See issue #52 + */ @Test - public void testUpdateWithClientSuppliedIdWhichDoesntExist() { - deleteToken("Patient", Patient.SP_IDENTIFIER, "urn:system", "testUpdateWithClientSuppliedIdWhichDoesntExist"); - - Patient p1 = new Patient(); - p1.addIdentifier().setSystem("urn:system").setValue("testUpdateWithClientSuppliedIdWhichDoesntExist"); - MethodOutcome outcome = ourClient.update().resource(p1).withId("testUpdateWithClientSuppliedIdWhichDoesntExist").execute(); - assertEquals(true, outcome.getCreated().booleanValue()); - IdDt p1Id = outcome.getId(); - - assertThat(p1Id.getValue(), containsString("Patient/testUpdateWithClientSuppliedIdWhichDoesntExist/_history")); - - Bundle actual = ourClient.search().forResource(Patient.class).where(Patient.IDENTIFIER.exactly().systemAndCode("urn:system", "testUpdateWithClientSuppliedIdWhichDoesntExist")).encodedJson().prettyPrint().execute(); - assertEquals(1, actual.size()); - assertEquals(p1Id.getIdPart(), actual.getEntries().get(0).getId().getIdPart()); - + public void testImagingStudyResources() throws Exception { + IGenericClient client = ourClient; + + int initialSize = client.search().forResource(ImagingStudy.class).execute().size(); + + String resBody = IOUtils.toString(CompleteResourceProviderTest.class.getResource("/imagingstudy.json")); + client.create().resource(resBody).execute(); + + int newSize = client.search().forResource(ImagingStudy.class).execute().size(); + + assertEquals(1, newSize - initialSize); + } + + /** + * See issue #52 + */ + @Test + public void testDiagnosticOrderResources() throws Exception { + IGenericClient client = ourClient; + + int initialSize = client.search().forResource(DiagnosticOrder.class).execute().size(); + + DiagnosticOrder res = new DiagnosticOrder(); + res.addIdentifier("urn:foo", "123"); + + client.create().resource(res).execute(); + + int newSize = client.search().forResource(DiagnosticOrder.class).execute().size(); + + assertEquals(1, newSize - initialSize); + + } + + + 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()) { + ourLog.info("Deleting resource: {}", next.getId()); + ourClient.delete().resource(next).execute(); + } + } + + private void deleteToken(String theResourceType, String theParamName, String theParamSystem, String theParamValue) { + Bundle resources = ourClient.search().forResource(theResourceType).where(new TokenClientParam(theParamName).exactly().systemAndCode(theParamSystem, theParamValue)).execute(); + for (IResource next : resources.toListOfResources()) { + ourLog.info("Deleting resource: {}", next.getId()); + ourClient.delete().resource(next).execute(); + } + } + @Test public void testCreateWithClientSuppliedId() { deleteToken("Patient", Patient.SP_IDENTIFIER, "urn:system", "testCreateWithId01"); @@ -130,134 +158,6 @@ public class CompleteResourceProviderTest { assertNotNull(history.getEntries().get(0).getResource()); } - @Test - public void testTryToCreateResourceWithReferenceThatDoesntExist() { - deleteToken("Patient", Patient.SP_IDENTIFIER, "urn:system", "testTryToCreateResourceWithReferenceThatDoesntExist01"); - - Patient p1 = new Patient(); - p1.addIdentifier().setSystem("urn:system").setValue("testTryToCreateResourceWithReferenceThatDoesntExist01"); - p1.addName().addFamily("testTryToCreateResourceWithReferenceThatDoesntExistFamily01").addGiven("testTryToCreateResourceWithReferenceThatDoesntExistGiven01"); - p1.setManagingOrganization(new ResourceReferenceDt("Organization/1323123232349875324987529835")); - - try { - ourClient.create(p1).getId(); - fail(); - } catch (InvalidRequestException e) { - assertThat(e.getMessage(), containsString("Organization/1323123232349875324987529835")); - } - - } - - @Test - public void testSaveAndRetrieveExistingNarrative() { - deleteToken("Patient", Patient.SP_IDENTIFIER, "urn:system", "testSaveAndRetrieveExistingNarrative01"); - - Patient p1 = new Patient(); - p1.getText().setStatus(NarrativeStatusEnum.GENERATED); - p1.getText().getDiv().setValueAsString("
HELLO WORLD
"); - p1.addIdentifier().setSystem("urn:system").setValue("testSaveAndRetrieveExistingNarrative01"); - - IdDt newId = ourClient.create(p1).getId(); - - Patient actual = ourClient.read(Patient.class, newId); - assertEquals("
HELLO WORLD
", actual.getText().getDiv().getValueAsString()); - } - - @Test - public void testSaveAndRetrieveWithoutNarrative() { - Patient p1 = new Patient(); - p1.addIdentifier().setSystem("urn:system").setValue("testSearchByResourceChain01"); - - IdDt newId = ourClient.create(p1).getId(); - - Patient actual = ourClient.read(Patient.class, newId); - assertThat(actual.getText().getDiv().getValueAsString(), containsString("IdentifiertestSearchByResourceChain01")); - } - - @Test - public void testSaveAndRetrieveWithContained() { - Patient p1 = new Patient(); - p1.addIdentifier().setSystem("urn:system").setValue("testSaveAndRetrieveWithContained01"); - - Organization o1 = new Organization(); - o1.addIdentifier().setSystem("urn:system").setValue("testSaveAndRetrieveWithContained02"); - - p1.getManagingOrganization().setResource(o1); - - IdDt newId = ourClient.create().resource(p1).execute().getId(); - - Patient actual = ourClient.read(Patient.class, newId); - assertEquals(1, actual.getContained().getContainedResources().size()); - assertThat(actual.getText().getDiv().getValueAsString(), containsString("IdentifiertestSaveAndRetrieveWithContained01")); - - Bundle b = ourClient.search().forResource("Patient").where(Patient.IDENTIFIER.exactly().systemAndCode("urn:system","testSaveAndRetrieveWithContained01")).execute(); - assertEquals(1, b.size()); - - } - - - @Test - public void testSearchByIdentifier() { - deleteToken("Patient", Patient.SP_IDENTIFIER, "urn:system", "testSearchByIdentifier01"); - deleteToken("Patient", Patient.SP_IDENTIFIER, "urn:system", "testSearchByIdentifier02"); - - Patient p1 = new Patient(); - p1.addIdentifier().setSystem("urn:system").setValue("testSearchByIdentifier01"); - p1.addName().addFamily("testSearchByIdentifierFamily01").addGiven("testSearchByIdentifierGiven01"); - IdDt p1Id = ourClient.create(p1).getId(); - - Patient p2 = new Patient(); - p2.addIdentifier().setSystem("urn:system").setValue("testSearchByIdentifier02"); - p2.addName().addFamily("testSearchByIdentifierFamily01").addGiven("testSearchByIdentifierGiven02"); - ourClient.create(p2).getId(); - - Bundle actual = ourClient.search().forResource(Patient.class).where(Patient.IDENTIFIER.exactly().systemAndCode("urn:system", "testSearchByIdentifier01")).encodedJson().prettyPrint().execute(); - assertEquals(1, actual.size()); - assertEquals(p1Id.getIdPart(), actual.getEntries().get(0).getId().getIdPart()); - } - - @Test - public void testSearchByIdentifierWithoutSystem() { - deleteToken("Patient", Patient.SP_IDENTIFIER, "", "testSearchByIdentifierWithoutSystem01"); - - Patient p1 = new Patient(); - p1.addIdentifier().setValue("testSearchByIdentifierWithoutSystem01"); - IdDt p1Id = ourClient.create(p1).getId(); - - Bundle actual = ourClient.search().forResource(Patient.class).where(Patient.IDENTIFIER.exactly().systemAndCode(null, "testSearchByIdentifierWithoutSystem01")).encodedJson().prettyPrint().execute(); - assertEquals(1, actual.size()); - assertEquals(p1Id.getIdPart(), actual.getEntries().get(0).getId().getIdPart()); - - } - - @Test - public void testUpdateRejectsInvalidTypes() throws InterruptedException { - deleteToken("Patient", Patient.SP_IDENTIFIER, "urn:system", "testUpdateRejectsInvalidTypes"); - - Patient p1 = new Patient(); - p1.addIdentifier("urn:system", "testUpdateRejectsInvalidTypes"); - p1.addName().addFamily("Tester").addGiven("testUpdateRejectsInvalidTypes"); - IdDt p1id = ourClient.create().resource(p1).execute().getId(); - - Organization p2 = new Organization(); - p2.getName().setValue("testUpdateRejectsInvalidTypes"); - try { - ourClient.update().resource(p2).withId("Organization/" + p1id.getIdPart()).execute(); - fail(); - } catch (UnprocessableEntityException e) { - // good - } - - try { - ourClient.update().resource(p2).withId("Patient/" + p1id.getIdPart()).execute(); - fail(); - } catch (UnprocessableEntityException e) { - // good - } - - } - - @Test public void testDeepChaining() { delete("Location", Location.SP_NAME, "testDeepChainingL1"); @@ -297,20 +197,86 @@ 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()) { - ourLog.info("Deleting resource: {}", next.getId()); - ourClient.delete().resource(next).execute(); - } + @Test + public void testSaveAndRetrieveExistingNarrative() { + deleteToken("Patient", Patient.SP_IDENTIFIER, "urn:system", "testSaveAndRetrieveExistingNarrative01"); + + Patient p1 = new Patient(); + p1.getText().setStatus(NarrativeStatusEnum.GENERATED); + p1.getText().getDiv().setValueAsString("
HELLO WORLD
"); + p1.addIdentifier().setSystem("urn:system").setValue("testSaveAndRetrieveExistingNarrative01"); + + IdDt newId = ourClient.create(p1).getId(); + + Patient actual = ourClient.read(Patient.class, newId); + assertEquals("
HELLO WORLD
", actual.getText().getDiv().getValueAsString()); } - private void deleteToken(String theResourceType, String theParamName, String theParamSystem, String theParamValue) { - Bundle resources = ourClient.search().forResource(theResourceType).where(new TokenClientParam(theParamName).exactly().systemAndCode(theParamSystem, theParamValue)).execute(); - for (IResource next : resources.toListOfResources()) { - ourLog.info("Deleting resource: {}", next.getId()); - ourClient.delete().resource(next).execute(); - } + @Test + public void testSaveAndRetrieveWithContained() { + Patient p1 = new Patient(); + p1.addIdentifier().setSystem("urn:system").setValue("testSaveAndRetrieveWithContained01"); + + Organization o1 = new Organization(); + o1.addIdentifier().setSystem("urn:system").setValue("testSaveAndRetrieveWithContained02"); + + p1.getManagingOrganization().setResource(o1); + + IdDt newId = ourClient.create().resource(p1).execute().getId(); + + Patient actual = ourClient.read(Patient.class, newId); + assertEquals(1, actual.getContained().getContainedResources().size()); + assertThat(actual.getText().getDiv().getValueAsString(), containsString("IdentifiertestSaveAndRetrieveWithContained01")); + + Bundle b = ourClient.search().forResource("Patient").where(Patient.IDENTIFIER.exactly().systemAndCode("urn:system", "testSaveAndRetrieveWithContained01")).execute(); + assertEquals(1, b.size()); + + } + + @Test + public void testSaveAndRetrieveWithoutNarrative() { + Patient p1 = new Patient(); + p1.addIdentifier().setSystem("urn:system").setValue("testSearchByResourceChain01"); + + IdDt newId = ourClient.create(p1).getId(); + + Patient actual = ourClient.read(Patient.class, newId); + assertThat(actual.getText().getDiv().getValueAsString(), containsString("IdentifiertestSearchByResourceChain01")); + } + + @Test + public void testSearchByIdentifier() { + deleteToken("Patient", Patient.SP_IDENTIFIER, "urn:system", "testSearchByIdentifier01"); + deleteToken("Patient", Patient.SP_IDENTIFIER, "urn:system", "testSearchByIdentifier02"); + + Patient p1 = new Patient(); + p1.addIdentifier().setSystem("urn:system").setValue("testSearchByIdentifier01"); + p1.addName().addFamily("testSearchByIdentifierFamily01").addGiven("testSearchByIdentifierGiven01"); + IdDt p1Id = ourClient.create(p1).getId(); + + Patient p2 = new Patient(); + p2.addIdentifier().setSystem("urn:system").setValue("testSearchByIdentifier02"); + p2.addName().addFamily("testSearchByIdentifierFamily01").addGiven("testSearchByIdentifierGiven02"); + ourClient.create(p2).getId(); + + Bundle actual = ourClient.search().forResource(Patient.class).where(Patient.IDENTIFIER.exactly().systemAndCode("urn:system", "testSearchByIdentifier01")).encodedJson().prettyPrint().execute(); + assertEquals(1, actual.size()); + assertEquals(p1Id.getIdPart(), actual.getEntries().get(0).getId().getIdPart()); + } + + @Test + public void testSearchByIdentifierWithoutSystem() { + deleteToken("Patient", Patient.SP_IDENTIFIER, "", "testSearchByIdentifierWithoutSystem01"); + + Patient p1 = new Patient(); + p1.addIdentifier().setValue("testSearchByIdentifierWithoutSystem01"); + IdDt p1Id = ourClient.create(p1).getId(); + + Bundle actual = ourClient.search().forResource(Patient.class).where(Patient.IDENTIFIER.exactly().systemAndCode(null, "testSearchByIdentifierWithoutSystem01")).encodedJson().prettyPrint() + .execute(); + assertEquals(1, actual.size()); + assertEquals(p1Id.getIdPart(), actual.getEntries().get(0).getId().getIdPart()); + } @Test @@ -348,6 +314,70 @@ public class CompleteResourceProviderTest { } + @Test + public void testTryToCreateResourceWithReferenceThatDoesntExist() { + deleteToken("Patient", Patient.SP_IDENTIFIER, "urn:system", "testTryToCreateResourceWithReferenceThatDoesntExist01"); + + Patient p1 = new Patient(); + p1.addIdentifier().setSystem("urn:system").setValue("testTryToCreateResourceWithReferenceThatDoesntExist01"); + p1.addName().addFamily("testTryToCreateResourceWithReferenceThatDoesntExistFamily01").addGiven("testTryToCreateResourceWithReferenceThatDoesntExistGiven01"); + p1.setManagingOrganization(new ResourceReferenceDt("Organization/1323123232349875324987529835")); + + try { + ourClient.create(p1).getId(); + fail(); + } catch (InvalidRequestException e) { + assertThat(e.getMessage(), containsString("Organization/1323123232349875324987529835")); + } + + } + + @Test + public void testUpdateRejectsInvalidTypes() throws InterruptedException { + deleteToken("Patient", Patient.SP_IDENTIFIER, "urn:system", "testUpdateRejectsInvalidTypes"); + + Patient p1 = new Patient(); + p1.addIdentifier("urn:system", "testUpdateRejectsInvalidTypes"); + p1.addName().addFamily("Tester").addGiven("testUpdateRejectsInvalidTypes"); + IdDt p1id = ourClient.create().resource(p1).execute().getId(); + + Organization p2 = new Organization(); + p2.getName().setValue("testUpdateRejectsInvalidTypes"); + try { + ourClient.update().resource(p2).withId("Organization/" + p1id.getIdPart()).execute(); + fail(); + } catch (UnprocessableEntityException e) { + // good + } + + try { + ourClient.update().resource(p2).withId("Patient/" + p1id.getIdPart()).execute(); + fail(); + } catch (UnprocessableEntityException e) { + // good + } + + } + + @Test + public void testUpdateWithClientSuppliedIdWhichDoesntExist() { + deleteToken("Patient", Patient.SP_IDENTIFIER, "urn:system", "testUpdateWithClientSuppliedIdWhichDoesntExist"); + + Patient p1 = new Patient(); + p1.addIdentifier().setSystem("urn:system").setValue("testUpdateWithClientSuppliedIdWhichDoesntExist"); + MethodOutcome outcome = ourClient.update().resource(p1).withId("testUpdateWithClientSuppliedIdWhichDoesntExist").execute(); + assertEquals(true, outcome.getCreated().booleanValue()); + IdDt p1Id = outcome.getId(); + + assertThat(p1Id.getValue(), containsString("Patient/testUpdateWithClientSuppliedIdWhichDoesntExist/_history")); + + Bundle actual = ourClient.search().forResource(Patient.class).where(Patient.IDENTIFIER.exactly().systemAndCode("urn:system", "testUpdateWithClientSuppliedIdWhichDoesntExist")).encodedJson() + .prettyPrint().execute(); + assertEquals(1, actual.size()); + assertEquals(p1Id.getIdPart(), actual.getEntries().get(0).getId().getIdPart()); + + } + @AfterClass public static void afterClass() throws Exception { ourServer.stop(); @@ -364,17 +394,17 @@ public class CompleteResourceProviderTest { if (true) { ourAppCtx = new ClassPathXmlApplicationContext("fhir-spring-test-config.xml"); - patientDao = (IFhirResourceDao) ourAppCtx.getBean("myPatientDao", IFhirResourceDao.class); + ourPatientDao = (IFhirResourceDao) ourAppCtx.getBean("myPatientDao", IFhirResourceDao.class); PatientResourceProvider patientRp = new PatientResourceProvider(); - patientRp.setDao(patientDao); + patientRp.setDao(ourPatientDao); - questionnaireDao = (IFhirResourceDao) ourAppCtx.getBean("myQuestionnaireDao", IFhirResourceDao.class); + ourQuestionnaireDao = (IFhirResourceDao) ourAppCtx.getBean("myQuestionnaireDao", IFhirResourceDao.class); QuestionnaireResourceProvider questionnaireRp = new QuestionnaireResourceProvider(); - questionnaireRp.setDao(questionnaireDao); + questionnaireRp.setDao(ourQuestionnaireDao); - observationDao = (IFhirResourceDao) ourAppCtx.getBean("myObservationDao", IFhirResourceDao.class); + ourObservationDao = (IFhirResourceDao) ourAppCtx.getBean("myObservationDao", IFhirResourceDao.class); ObservationResourceProvider observationRp = new ObservationResourceProvider(); - observationRp.setDao(observationDao); + observationRp.setDao(ourObservationDao); IFhirResourceDao locationDao = (IFhirResourceDao) ourAppCtx.getBean("myLocationDao", IFhirResourceDao.class); LocationResourceProvider locationRp = new LocationResourceProvider(); @@ -388,7 +418,23 @@ public class CompleteResourceProviderTest { OrganizationResourceProvider organizationRp = new OrganizationResourceProvider(); organizationRp.setDao(organizationDao); - restServer.setResourceProviders(encounterRp, locationRp, patientRp, questionnaireRp, observationRp, organizationRp); + IFhirResourceDao imagingStudyDao = (IFhirResourceDao) ourAppCtx.getBean("myImagingStudyDao", IFhirResourceDao.class); + ImagingStudyResourceProvider imagingStudyRp = new ImagingStudyResourceProvider(); + imagingStudyRp.setDao(imagingStudyDao); + + IFhirResourceDao diagnosticOrderDao =ourAppCtx.getBean("myDiagnosticOrderDao", IFhirResourceDao.class); + DiagnosticOrderResourceProvider diagnosticOrderRp = new DiagnosticOrderResourceProvider(); + diagnosticOrderRp.setDao(diagnosticOrderDao); + + IFhirResourceDao documentManifestDao =ourAppCtx.getBean("myDocumentManifestDao", IFhirResourceDao.class); + DocumentManifestResourceProvider documentManifestRp = new DocumentManifestResourceProvider(); + documentManifestRp.setDao(documentManifestDao); + + IFhirResourceDao 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.getFhirContext().setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator()); IFhirSystemDao systemDao = (IFhirSystemDao) ourAppCtx.getBean("mySystemDao", IFhirSystemDao.class); @@ -414,7 +460,7 @@ public class CompleteResourceProviderTest { } ourCtx = restServer.getFhirContext(); -// ourCtx.getRestfulClientFactory().setProxy("localhost", 8888); + // ourCtx.getRestfulClientFactory().setProxy("localhost", 8888); ourClient = ourCtx.newRestfulGenericClient(serverBase); // ourClient = ourCtx.newRestfulGenericClient("http://fhir.healthintersections.com.au/open"); diff --git a/hapi-fhir-jpaserver-test/src/test/resources/imagingstudy.json b/hapi-fhir-jpaserver-test/src/test/resources/imagingstudy.json new file mode 100644 index 00000000000..7f7e3d51bf6 --- /dev/null +++ b/hapi-fhir-jpaserver-test/src/test/resources/imagingstudy.json @@ -0,0 +1,2 @@ +{ +"resourceType" : "ImagingStudy","text" : {"status" : "generated","div" : "
Image 1 from Series 3: CT Images on Patient MINT (MINT1234) taken at 1-Jan 2011 01:20 AM
"},"dateTime" : "2011-01-01T11:01:20","uid" : "urn:oid:2.16.124.113543.6003.1154777499.30246.19789.3503430045","numberOfSeries" : 1,"numberOfInstances" : 1,"series" : [{"number" : 3,"modality" : "CT","uid" : "urn:oid:2.16.124.113543.6003.2588828330.45298.17418.2723805630","description" : "CT Surview 180","numberOfInstances" : 1,"instance" : [{"number" : 1,"uid" : "urn:oid:2.16.124.113543.6003.189642796.63084.16748.2599092903","sopclass" : "urn:oid:1.2.840.10008.5.1.4.1.1.2","url" : "http://localhost/fhir/Binary/@1.2.840.11361907579238403408700.3.0.14.19970327150033"}]}]} \ No newline at end of file diff --git a/hapi-fhir-structures-dstu/.settings/org.eclipse.wst.common.project.facet.core.xml b/hapi-fhir-structures-dstu/.settings/org.eclipse.wst.common.project.facet.core.xml index 4f92af543f1..5c9bd7532ab 100644 --- a/hapi-fhir-structures-dstu/.settings/org.eclipse.wst.common.project.facet.core.xml +++ b/hapi-fhir-structures-dstu/.settings/org.eclipse.wst.common.project.facet.core.xml @@ -1,5 +1,5 @@ - + diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/GenericClientTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/GenericClientTest.java index e93b656375d..b83f3e23fda 100644 --- a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/GenericClientTest.java +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/GenericClientTest.java @@ -4,6 +4,7 @@ import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; import static org.mockito.Mockito.*; +import java.io.IOException; import java.io.StringReader; import java.net.URLEncoder; import java.nio.charset.Charset; @@ -23,6 +24,7 @@ import org.apache.http.client.methods.HttpPut; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.message.BasicHeader; import org.apache.http.message.BasicStatusLine; +import org.apache.http.util.EncodingUtils; import org.hamcrest.core.StringContains; import org.junit.Before; import org.junit.BeforeClass; @@ -177,25 +179,133 @@ public class GenericClientTest { assertEquals("44", outcome.getId().getIdPart()); assertEquals("22", outcome.getId().getVersionIdPart()); + int count = 0; + assertEquals("http://example.com/fhir/Patient", capt.getValue().getURI().toString()); assertEquals("POST", capt.getValue().getMethod()); Header catH = capt.getValue().getFirstHeader("Category"); assertNotNull(Arrays.asList(capt.getValue().getAllHeaders()).toString(), catH); assertEquals("urn:happytag; label=\"This is a happy resource\"; scheme=\"http://hl7.org/fhir/tag\"", catH.getValue()); - + 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()); + count++; + /* * Try fluent options */ when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8"))); client.create().resource(p1).withId("123").execute(); assertEquals("http://example.com/fhir/Patient/123", capt.getAllValues().get(1).getURI().toString()); - + 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()); + count++; + String resourceText = " "; when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8"))); client.create().resource(resourceText).withId("123").execute(); assertEquals("http://example.com/fhir/Patient/123", capt.getAllValues().get(2).getURI().toString()); assertEquals(resourceText, IOUtils.toString(((HttpPost) capt.getAllValues().get(2)).getEntity().getContent())); + 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()); + count++; + } + @Test + public void testCreateWithStringAutoDetectsEncoding() throws Exception { + + Patient p1 = new Patient(); + p1.addIdentifier("foo:bar", "12345"); + p1.addName().addFamily("Smith").addGiven("John"); + + ArgumentCaptor 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 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 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 @@ -503,8 +613,7 @@ public class GenericClientTest { capt.getValue().getURI().toString()); } - - + @Test public void testSearchWithAbsoluteUrl() throws Exception { @@ -518,7 +627,9 @@ public class GenericClientTest { 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")); + 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", @@ -527,7 +638,6 @@ public class GenericClientTest { assertEquals(1, response.size()); } - @Test public void testSearchWithAbsoluteUrlAndType() throws Exception { @@ -541,7 +651,10 @@ public class GenericClientTest { 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")); + 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", @@ -549,7 +662,7 @@ public class GenericClientTest { assertEquals(1, response.size()); } - + @SuppressWarnings("unused") @Test public void testSearchByNumberExact() throws Exception { @@ -975,19 +1088,26 @@ public class GenericClientTest { p1.setId("44"); client.update().resource(p1).execute(); + int count = 0; + assertEquals(1, capt.getAllValues().size()); - + 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()); + count++; + MethodOutcome outcome = client.update().resource(p1).execute(); assertEquals("44", outcome.getId().getIdPart()); assertEquals("22", outcome.getId().getVersionIdPart()); assertEquals(2, capt.getAllValues().size()); - + assertEquals("http://example.com/fhir/Patient/44", capt.getValue().getURI().toString()); assertEquals("PUT", capt.getValue().getMethod()); Header catH = capt.getValue().getFirstHeader("Category"); assertNotNull(Arrays.asList(capt.getValue().getAllHeaders()).toString(), catH); assertEquals("urn:happytag; label=\"This is a happy resource\"; scheme=\"http://hl7.org/fhir/tag\"", catH.getValue()); + 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()); /* * Try fluent options diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ServerFeaturesTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ServerFeaturesTest.java index b8cd559dd57..0435977c5f9 100644 --- a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ServerFeaturesTest.java +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ServerFeaturesTest.java @@ -25,6 +25,7 @@ import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; +import ca.uhn.fhir.model.api.Bundle; import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.dstu.composite.HumanNameDt; import ca.uhn.fhir.model.dstu.composite.IdentifierDt; @@ -223,6 +224,25 @@ public class ServerFeaturesTest { } + @Test + public void testSearchReturnWithAbsoluteIdSpecified() throws Exception { + + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/?_query=findPatientsWithAbsoluteIdSpecified"); + httpGet.addHeader("Accept", Constants.CT_FHIR_XML + "; pretty=true"); + CloseableHttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + + Bundle bundle = servlet.getFhirContext().newXmlParser().parseBundle(responseContent); + assertEquals(1,bundle.size()); + + assertEquals("http://absolute.com/Patient/123", bundle.getEntries().get(0).getId().getValue()); + assertEquals("http://absolute.com/Patient/123/_history/22", bundle.getEntries().get(0).getLinkSelf().getValue()); + + } + @Test public void testSearchWithWildcardRetVal() throws Exception { @@ -345,6 +365,15 @@ public class ServerFeaturesTest { return Collections.singletonList(p); } + @Search(queryName = "findPatientsWithAbsoluteIdSpecified") + public List findPatientsWithAbsoluteIdSpecified() { + Patient p = new Patient(); + p.addIdentifier().setSystem("foo"); + p.setId("http://absolute.com/Patient/123/_history/22"); + return Collections.singletonList(p); + } + + @Override public Class getResourceType() { return Patient.class; diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 97e9619a513..52a96f7f8a8 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -102,6 +102,30 @@ invalid dates, e.g. "2001-15-01". Thanks to Joe Athman for reporting and helping to come up with a fix! + + When using Generic Client, if performing a + or operation using a String as the resource body, + the client will auto-detect the FHIR encoding style and send an appropriate Content-Type header. + + + JPA module (and public HAPI-FHIR test server) were unable to process resource types + where at least one search parameter has no path specified. These now correctly save + (although the server does not yet process these params, and it should). Thanks to + GitHub user shvoidlee for reporting and help with analysis! + + + Generic/Fluent Client "create" and "update" method requests were not setting a content type header + + + DateDt left precision value as null in the constructor + . + + + RESTful server now doesn't overwrite resource IDs if they are absolute. In other words, if + a server's Resource Provider returns a resource with ID "Patient/123" it will be translated to + "[base url]/Patient/123" but if the RP returns ID "http://foo/Patient/123" the ID will be + returned exactly as is. Thanks to Bill de Beaubien for the suggestion! +