From a989a746b0dd8185eb18cbe312ff4469fed0c270 Mon Sep 17 00:00:00 2001 From: James Agnew Date: Fri, 20 Sep 2019 09:38:29 -0400 Subject: [PATCH] Fix #1494 - Upgrade to new :recurse syntax for R4 include/revinclude statements --- .../java/ca/uhn/fhir/model/api/Include.java | 28 +- .../java/ca/uhn/fhir/rest/api/Constants.java | 3 + .../fhir/rest/client/impl/GenericClient.java | 12 +- .../rest/client/method/IncludeParameter.java | 18 +- .../rest/server/method/IncludeParameter.java | 3 +- .../ca/uhn/fhir/rest/client/ClientR4Test.java | 2 +- .../fhir/rest/client/GenericClientR4Test.java | 2 +- .../ca/uhn/fhir/rest/server/IncludeTest.java | 373 +++++++++--------- src/changes/changes.xml | 8 + 9 files changed, 248 insertions(+), 201 deletions(-) diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/Include.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/Include.java index 18ca85bcba7..4f5d2ad1abb 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/Include.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/Include.java @@ -40,7 +40,7 @@ public class Include implements Serializable { private static final long serialVersionUID = 1L; private final boolean myImmutable; - private boolean myRecurse; + private boolean myIterate; private String myValue; /** @@ -59,12 +59,12 @@ public class Include implements Serializable { * * @param theValue * The _include value, e.g. "Patient:name" - * @param theRecurse + * @param theIterate * Should the include recurse */ - public Include(String theValue, boolean theRecurse) { + public Include(String theValue, boolean theIterate) { myValue = theValue; - myRecurse = theRecurse; + myIterate = theIterate; myImmutable = false; } @@ -73,12 +73,12 @@ public class Include implements Serializable { * * @param theValue * The _include value, e.g. "Patient:name" - * @param theRecurse + * @param theIterate * Should the include recurse */ - public Include(String theValue, boolean theRecurse, boolean theImmutable) { + public Include(String theValue, boolean theIterate, boolean theImmutable) { myValue = theValue; - myRecurse = theRecurse; + myIterate = theIterate; myImmutable = theImmutable; } @@ -111,7 +111,7 @@ public class Include implements Serializable { return false; } Include other = (Include) obj; - if (myRecurse != other.myRecurse) { + if (myIterate != other.myIterate) { return false; } if (myValue == null) { @@ -177,7 +177,7 @@ public class Include implements Serializable { public int hashCode() { final int prime = 31; int result = 1; - result = prime * result + (myRecurse ? 1231 : 1237); + result = prime * result + (myIterate ? 1231 : 1237); result = prime * result + ((myValue == null) ? 0 : myValue.hashCode()); return result; } @@ -190,7 +190,7 @@ public class Include implements Serializable { } public boolean isRecurse() { - return myRecurse; + return myIterate; } /** @@ -199,7 +199,7 @@ public class Include implements Serializable { * @return Returns a reference to this for easy method chaining */ public Include setRecurse(boolean theRecurse) { - myRecurse = theRecurse; + myIterate = theRecurse; return this; } @@ -214,7 +214,7 @@ public class Include implements Serializable { * Return a new */ public Include toLocked() { - Include retVal = new Include(myValue, myRecurse, true); + Include retVal = new Include(myValue, myIterate, true); return retVal; } @@ -222,7 +222,7 @@ public class Include implements Serializable { public String toString() { ToStringBuilder builder = new ToStringBuilder(this); builder.append("value", myValue); - builder.append("recurse", myRecurse); + builder.append("iterate", myIterate); return builder.toString(); } @@ -273,7 +273,7 @@ public class Include implements Serializable { b.append(':'); b.append(theResourceType); } - Include retVal = new Include(b.toString(), myRecurse, myImmutable); + Include retVal = new Include(b.toString(), myIterate, myImmutable); return retVal; } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/api/Constants.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/api/Constants.java index 4fe703209db..907f04bca90 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/api/Constants.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/api/Constants.java @@ -151,6 +151,8 @@ public class Constants { public static final String PARAM_INCLUDE = "_include"; public static final String PARAM_INCLUDE_QUALIFIER_RECURSE = ":recurse"; public static final String PARAM_INCLUDE_RECURSE = "_include" + PARAM_INCLUDE_QUALIFIER_RECURSE; + public static final String PARAM_INCLUDE_QUALIFIER_ITERATE = ":iterate"; + public static final String PARAM_INCLUDE_ITERATE = "_include" + PARAM_INCLUDE_QUALIFIER_ITERATE; public static final String PARAM_LASTUPDATED = "_lastUpdated"; public static final String PARAM_NARRATIVE = "_narrative"; public static final String PARAM_PAGINGACTION = "_getpages"; @@ -163,6 +165,7 @@ public class Constants { public static final String PARAM_RESPONSE_URL = "response-url"; //Used in messaging public static final String PARAM_REVINCLUDE = "_revinclude"; public static final String PARAM_REVINCLUDE_RECURSE = PARAM_REVINCLUDE + PARAM_INCLUDE_QUALIFIER_RECURSE; + public static final String PARAM_REVINCLUDE_ITERATE = PARAM_REVINCLUDE + PARAM_INCLUDE_QUALIFIER_ITERATE; public static final String PARAM_SEARCH = "_search"; public static final String PARAM_SECURITY = "_security"; public static final String PARAM_SINCE = "_since"; diff --git a/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/impl/GenericClient.java b/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/impl/GenericClient.java index 7838055f2c5..6aebc0982f0 100644 --- a/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/impl/GenericClient.java +++ b/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/impl/GenericClient.java @@ -1761,7 +1761,11 @@ public class GenericClient extends BaseClient implements IGenericClient { for (Include next : myInclude) { if (next.isRecurse()) { - addParam(params, Constants.PARAM_INCLUDE_RECURSE, next.getValue()); + if (myContext.getVersion().getVersion().isEqualOrNewerThan(FhirVersionEnum.R4)) { + addParam(params, Constants.PARAM_INCLUDE_ITERATE, next.getValue()); + } else { + addParam(params, Constants.PARAM_INCLUDE_RECURSE, next.getValue()); + } } else { addParam(params, Constants.PARAM_INCLUDE, next.getValue()); } @@ -1769,7 +1773,11 @@ public class GenericClient extends BaseClient implements IGenericClient { for (Include next : myRevInclude) { if (next.isRecurse()) { - addParam(params, Constants.PARAM_REVINCLUDE_RECURSE, next.getValue()); + if (myContext.getVersion().getVersion().isEqualOrNewerThan(FhirVersionEnum.R4)) { + addParam(params, Constants.PARAM_REVINCLUDE_ITERATE, next.getValue()); + } else { + addParam(params, Constants.PARAM_REVINCLUDE_RECURSE, next.getValue()); + } } else { addParam(params, Constants.PARAM_REVINCLUDE, next.getValue()); } diff --git a/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/method/IncludeParameter.java b/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/method/IncludeParameter.java index 607fc431fdc..949816c5060 100644 --- a/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/method/IncludeParameter.java +++ b/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/method/IncludeParameter.java @@ -23,6 +23,7 @@ import java.util.*; import ca.uhn.fhir.context.ConfigurationException; import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.FhirVersionEnum; import ca.uhn.fhir.model.api.Include; import ca.uhn.fhir.rest.annotation.IncludeParam; import ca.uhn.fhir.rest.api.*; @@ -64,23 +65,30 @@ class IncludeParameter extends BaseQueryParameter { if (myInstantiableCollectionType == null) { if (mySpecType == Include.class) { - convertAndAddIncludeToList(retVal, (Include) theObject); + convertAndAddIncludeToList(retVal, (Include) theObject, theContext); } else { retVal.add(QualifiedParamList.singleton(((String) theObject))); } } else { Collection val = (Collection) theObject; for (Include include : val) { - convertAndAddIncludeToList(retVal, include); + convertAndAddIncludeToList(retVal, include, theContext); } } return retVal; } - private void convertAndAddIncludeToList(ArrayList retVal, Include include) { - String qualifier = include.isRecurse() ? Constants.PARAM_INCLUDE_QUALIFIER_RECURSE : null; - retVal.add(QualifiedParamList.singleton(qualifier, include.getValue())); + private void convertAndAddIncludeToList(ArrayList theQualifiedParamLists, Include theInclude, FhirContext theContext) { + String qualifier = null; + if (theInclude.isRecurse()) { + if (theContext.getVersion().getVersion().isEqualOrNewerThan(FhirVersionEnum.R4)) { + qualifier = Constants.PARAM_INCLUDE_QUALIFIER_ITERATE; + } else { + qualifier = Constants.PARAM_INCLUDE_QUALIFIER_RECURSE; + } + } + theQualifiedParamLists.add(QualifiedParamList.singleton(qualifier, theInclude.getValue())); } public Set getAllow() { diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/IncludeParameter.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/IncludeParameter.java index 10794d65b8b..2c9c6de0767 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/IncludeParameter.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/IncludeParameter.java @@ -136,7 +136,8 @@ class IncludeParameter extends BaseQueryParameter { throw new InvalidRequestException(theContext.getLocalizer().getMessage(IncludeParameter.class, "orIncludeInRequest")); } - boolean recurse = Constants.PARAM_INCLUDE_QUALIFIER_RECURSE.equals(nextParamList.getQualifier()); + String qualifier = nextParamList.getQualifier(); + boolean recurse = Constants.PARAM_INCLUDE_QUALIFIER_RECURSE.equals(qualifier) || Constants.PARAM_INCLUDE_QUALIFIER_ITERATE.equals(qualifier); String value = nextParamList.get(0); if (myAllow != null && !myAllow.isEmpty()) { diff --git a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/client/ClientR4Test.java b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/client/ClientR4Test.java index 6090d4961ae..c83eef14a6e 100644 --- a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/client/ClientR4Test.java +++ b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/client/ClientR4Test.java @@ -924,7 +924,7 @@ public class ClientR4Test { ITestClient client = ourCtx.newRestfulClient(ITestClient.class, "http://foo"); client.getPatientWithIncludes(new StringParam("aaa"), Arrays.asList(new Include[]{new Include("inc1"), new Include("inc2", true), new Include("inc3", true)})); - assertEquals("http://foo/Patient?withIncludes=aaa&_include=inc1&_include%3Arecurse=inc2&_include%3Arecurse=inc3", capt.getValue().getURI().toString()); + assertEquals("http://foo/Patient?withIncludes=aaa&_include=inc1&_include%3Aiterate=inc2&_include%3Aiterate=inc3", capt.getValue().getURI().toString()); } diff --git a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/client/GenericClientR4Test.java b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/client/GenericClientR4Test.java index ef5011187ed..c7adb44e2c1 100644 --- a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/client/GenericClientR4Test.java +++ b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/client/GenericClientR4Test.java @@ -1451,7 +1451,7 @@ public class GenericClientR4Test { .returnBundle(Bundle.class) .execute(); - assertEquals("http://example.com/fhir/EpisodeOfCare?patient=123&_revinclude=Encounter%3Aepisode-of-care&_revinclude%3Arecurse=Observation%3Aencounter", + assertEquals("http://example.com/fhir/EpisodeOfCare?patient=123&_revinclude=Encounter%3Aepisode-of-care&_revinclude%3Aiterate=Observation%3Aencounter", capt.getAllValues().get(idx).getURI().toString()); idx++; diff --git a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/IncludeTest.java b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/IncludeTest.java index b28afb9b60a..b99d57cf3c9 100644 --- a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/IncludeTest.java +++ b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/IncludeTest.java @@ -1,28 +1,5 @@ package ca.uhn.fhir.rest.server; -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.hamcrest.Matchers.containsString; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; - -import java.util.*; -import java.util.concurrent.TimeUnit; - -import ca.uhn.fhir.rest.api.EncodingEnum; -import ca.uhn.fhir.test.utilities.JettyUtil; -import org.apache.commons.io.IOUtils; -import org.apache.http.HttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.servlet.ServletHandler; -import org.eclipse.jetty.servlet.ServletHolder; -import org.hl7.fhir.r4.model.*; -import org.junit.*; - import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.api.BundleInclusionRule; import ca.uhn.fhir.model.api.Include; @@ -30,129 +7,156 @@ import ca.uhn.fhir.model.api.annotation.Child; import ca.uhn.fhir.model.api.annotation.Extension; import ca.uhn.fhir.model.api.annotation.ResourceDef; import ca.uhn.fhir.model.primitive.StringDt; -import ca.uhn.fhir.rest.annotation.*; -import ca.uhn.fhir.util.*; +import ca.uhn.fhir.rest.annotation.IncludeParam; +import ca.uhn.fhir.rest.annotation.RequiredParam; +import ca.uhn.fhir.rest.annotation.Search; +import ca.uhn.fhir.rest.api.Constants; +import ca.uhn.fhir.rest.api.EncodingEnum; +import ca.uhn.fhir.test.utilities.JettyUtil; +import ca.uhn.fhir.util.BundleUtil; +import ca.uhn.fhir.util.ElementUtil; +import ca.uhn.fhir.util.TestUtil; +import org.apache.commons.io.IOUtils; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.hl7.fhir.r4.model.*; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.util.*; +import java.util.concurrent.TimeUnit; + +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.containsString; +import static org.junit.Assert.*; public class IncludeTest { + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(IncludeTest.class); private static CloseableHttpClient ourClient; private static FhirContext ourCtx; - private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(IncludeTest.class); private static int ourPort; private static Server ourServer; @Test public void testBadInclude() throws Exception { HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?name=Hello&_include=foo&_include=baz"); - HttpResponse status = ourClient.execute(httpGet); - assertEquals(400, status.getStatusLine().getStatusCode()); - String responseContent = IOUtils.toString(status.getEntity().getContent()); - IOUtils.closeQuietly(status.getEntity().getContent()); + try (CloseableHttpResponse status = ourClient.execute(httpGet)) { + assertEquals(400, status.getStatusLine().getStatusCode()); + String responseContent = IOUtils.toString(status.getEntity().getContent()); - ourLog.info(responseContent); - assertThat(responseContent, containsString("Invalid _include parameter value")); + ourLog.info(responseContent); + assertThat(responseContent, containsString("Invalid _include parameter value")); + } } @Test public void testIIncludedResourcesNonContained() throws Exception { HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=normalInclude&_pretty=true"); - HttpResponse status = ourClient.execute(httpGet); - String responseContent = IOUtils.toString(status.getEntity().getContent()); - IOUtils.closeQuietly(status.getEntity().getContent()); + try (CloseableHttpResponse status = ourClient.execute(httpGet)) { + String responseContent = IOUtils.toString(status.getEntity().getContent()); - assertEquals(200, status.getStatusLine().getStatusCode()); - Bundle bundle = ourCtx.newXmlParser().parseResource(Bundle.class, responseContent); + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourCtx.newXmlParser().parseResource(Bundle.class, responseContent); - ourLog.info(responseContent); + ourLog.info(responseContent); - assertEquals(3, bundle.getEntry().size()); - - assertEquals(("Patient/p1"), bundle.getEntry().get(0).getResource().getIdElement().toUnqualifiedVersionless().getValue()); - assertEquals(("Patient/p2"), bundle.getEntry().get(1).getResource().getIdElement().toUnqualifiedVersionless().getValue()); - assertEquals(("Organization/o1"), bundle.getEntry().get(2).getResource().getIdElement().toUnqualifiedVersionless().getValue()); + assertEquals(3, bundle.getEntry().size()); - Patient p1 = (Patient) bundle.getEntry().get(0).getResource(); - assertEquals(0, p1.getContained().size()); + assertEquals(("Patient/p1"), bundle.getEntry().get(0).getResource().getIdElement().toUnqualifiedVersionless().getValue()); + assertEquals(("Patient/p2"), bundle.getEntry().get(1).getResource().getIdElement().toUnqualifiedVersionless().getValue()); + assertEquals(("Organization/o1"), bundle.getEntry().get(2).getResource().getIdElement().toUnqualifiedVersionless().getValue()); - Patient p2 = (Patient) bundle.getEntry().get(1).getResource(); - assertEquals(0, p2.getContained().size()); + Patient p1 = (Patient) bundle.getEntry().get(0).getResource(); + assertEquals(0, p1.getContained().size()); + Patient p2 = (Patient) bundle.getEntry().get(1).getResource(); + assertEquals(0, p2.getContained().size()); + + } } @Test public void testIIncludedResourcesNonContainedInDeclaredExtension() throws Exception { HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=declaredExtInclude&_pretty=true"); - HttpResponse status = ourClient.execute(httpGet); - String responseContent = IOUtils.toString(status.getEntity().getContent()); - IOUtils.closeQuietly(status.getEntity().getContent()); + try (CloseableHttpResponse status = ourClient.execute(httpGet)) { + String responseContent = IOUtils.toString(status.getEntity().getContent()); - assertEquals(200, status.getStatusLine().getStatusCode()); - Bundle bundle = ourCtx.newXmlParser().parseResource(Bundle.class, responseContent); + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourCtx.newXmlParser().parseResource(Bundle.class, responseContent); - ourLog.info(responseContent); + ourLog.info(responseContent); - assertEquals(4, bundle.getEntry().size()); - assertEquals(("Patient/p1"), bundle.getEntry().get(0).getResource().getIdElement().toUnqualifiedVersionless().getValue()); - assertEquals(("Patient/p2"), bundle.getEntry().get(1).getResource().getIdElement().toUnqualifiedVersionless().getValue()); - assertEquals(("Organization/o1"), bundle.getEntry().get(2).getResource().getIdElement().toUnqualifiedVersionless().getValue()); - assertEquals(("Organization/o2"), bundle.getEntry().get(3).getResource().getIdElement().toUnqualifiedVersionless().getValue()); + assertEquals(4, bundle.getEntry().size()); + assertEquals(("Patient/p1"), bundle.getEntry().get(0).getResource().getIdElement().toUnqualifiedVersionless().getValue()); + assertEquals(("Patient/p2"), bundle.getEntry().get(1).getResource().getIdElement().toUnqualifiedVersionless().getValue()); + assertEquals(("Organization/o1"), bundle.getEntry().get(2).getResource().getIdElement().toUnqualifiedVersionless().getValue()); + assertEquals(("Organization/o2"), bundle.getEntry().get(3).getResource().getIdElement().toUnqualifiedVersionless().getValue()); - Patient p1 = (Patient) bundle.getEntry().get(0).getResource(); - assertEquals(0, p1.getContained().size()); + Patient p1 = (Patient) bundle.getEntry().get(0).getResource(); + assertEquals(0, p1.getContained().size()); - Patient p2 = (Patient) bundle.getEntry().get(1).getResource(); - assertEquals(0, p2.getContained().size()); + Patient p2 = (Patient) bundle.getEntry().get(1).getResource(); + assertEquals(0, p2.getContained().size()); + } } @Test public void testIIncludedResourcesNonContainedInExtension() throws Exception { HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=extInclude&_pretty=true"); - HttpResponse status = ourClient.execute(httpGet); - String responseContent = IOUtils.toString(status.getEntity().getContent()); - IOUtils.closeQuietly(status.getEntity().getContent()); + try (CloseableHttpResponse status = ourClient.execute(httpGet)) { + String responseContent = IOUtils.toString(status.getEntity().getContent()); - assertEquals(200, status.getStatusLine().getStatusCode()); - Bundle bundle = ourCtx.newXmlParser().parseResource(Bundle.class, responseContent); + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourCtx.newXmlParser().parseResource(Bundle.class, responseContent); - ourLog.info(responseContent); + ourLog.info(responseContent); - assertEquals(3, bundle.getEntry().size()); - assertEquals(("Patient/p1"), bundle.getEntry().get(0).getResource().getIdElement().toUnqualifiedVersionless().getValue()); - assertEquals(("Patient/p2"), bundle.getEntry().get(1).getResource().getIdElement().toUnqualifiedVersionless().getValue()); - assertEquals(("Organization/o1"), bundle.getEntry().get(2).getResource().getIdElement().toUnqualifiedVersionless().getValue()); + assertEquals(3, bundle.getEntry().size()); + assertEquals(("Patient/p1"), bundle.getEntry().get(0).getResource().getIdElement().toUnqualifiedVersionless().getValue()); + assertEquals(("Patient/p2"), bundle.getEntry().get(1).getResource().getIdElement().toUnqualifiedVersionless().getValue()); + assertEquals(("Organization/o1"), bundle.getEntry().get(2).getResource().getIdElement().toUnqualifiedVersionless().getValue()); - Patient p1 = (Patient) bundle.getEntry().get(0).getResource(); - assertEquals(0, p1.getContained().size()); + Patient p1 = (Patient) bundle.getEntry().get(0).getResource(); + assertEquals(0, p1.getContained().size()); - Patient p2 = (Patient) bundle.getEntry().get(1).getResource(); - assertEquals(0, p2.getContained().size()); + Patient p2 = (Patient) bundle.getEntry().get(1).getResource(); + assertEquals(0, p2.getContained().size()); + } } @Test public void testIIncludedResourcesNonContainedInExtensionJson() throws Exception { HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=extInclude&_pretty=true&_format=json"); - HttpResponse status = ourClient.execute(httpGet); - String responseContent = IOUtils.toString(status.getEntity().getContent()); - IOUtils.closeQuietly(status.getEntity().getContent()); + try (CloseableHttpResponse status = ourClient.execute(httpGet)) { + String responseContent = IOUtils.toString(status.getEntity().getContent()); - assertEquals(200, status.getStatusLine().getStatusCode()); - Bundle bundle = ourCtx.newJsonParser().parseResource(Bundle.class, responseContent); + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourCtx.newJsonParser().parseResource(Bundle.class, responseContent); - ourLog.info(responseContent); + ourLog.info(responseContent); - assertEquals(3, bundle.getEntry().size()); - assertEquals("Patient/p1", bundle.getEntry().get(0).getResource().getIdElement().toUnqualifiedVersionless().getValue()); - assertEquals("Patient/p2", bundle.getEntry().get(1).getResource().getIdElement().toUnqualifiedVersionless().getValue()); - assertEquals("Organization/o1", bundle.getEntry().get(2).getResource().getIdElement().toUnqualifiedVersionless().getValue()); + assertEquals(3, bundle.getEntry().size()); + assertEquals("Patient/p1", bundle.getEntry().get(0).getResource().getIdElement().toUnqualifiedVersionless().getValue()); + assertEquals("Patient/p2", bundle.getEntry().get(1).getResource().getIdElement().toUnqualifiedVersionless().getValue()); + assertEquals("Organization/o1", bundle.getEntry().get(2).getResource().getIdElement().toUnqualifiedVersionless().getValue()); - Patient p1 = (Patient) bundle.getEntry().get(0).getResource(); - assertEquals(0, p1.getContained().size()); + Patient p1 = (Patient) bundle.getEntry().get(0).getResource(); + assertEquals(0, p1.getContained().size()); - Patient p2 = (Patient) bundle.getEntry().get(1).getResource(); - assertEquals(0, p2.getContained().size()); + Patient p2 = (Patient) bundle.getEntry().get(1).getResource(); + assertEquals(0, p2.getContained().size()); + } } @Test @@ -189,106 +193,73 @@ public class IncludeTest { @Test public void testNoIncludes() throws Exception { HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?name=Hello"); - HttpResponse status = ourClient.execute(httpGet); - String responseContent = IOUtils.toString(status.getEntity().getContent()); - IOUtils.closeQuietly(status.getEntity().getContent()); + try (CloseableHttpResponse status = ourClient.execute(httpGet)) { + String responseContent = IOUtils.toString(status.getEntity().getContent()); - assertEquals(200, status.getStatusLine().getStatusCode()); - Bundle bundle = ourCtx.newXmlParser().parseResource(Bundle.class, responseContent); - assertEquals(1, bundle.getEntry().size()); + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourCtx.newXmlParser().parseResource(Bundle.class, responseContent); + assertEquals(1, bundle.getEntry().size()); - Patient p = BundleUtil.toListOfResourcesOfType(ourCtx, bundle, Patient.class).get(0); - assertEquals(0, p.getName().size()); - assertEquals("Hello", p.getIdElement().getIdPart()); + Patient p = BundleUtil.toListOfResourcesOfType(ourCtx, bundle, Patient.class).get(0); + assertEquals(0, p.getName().size()); + assertEquals("Hello", p.getIdElement().getIdPart()); + } } @Test public void testOneInclude() throws Exception { HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?name=Hello&_include=foo"); - HttpResponse status = ourClient.execute(httpGet); - String responseContent = IOUtils.toString(status.getEntity().getContent()); - IOUtils.closeQuietly(status.getEntity().getContent()); + try (CloseableHttpResponse status = ourClient.execute(httpGet)) { + String responseContent = IOUtils.toString(status.getEntity().getContent()); - assertEquals(200, status.getStatusLine().getStatusCode()); - Bundle bundle = ourCtx.newXmlParser().parseResource(Bundle.class, responseContent); - assertEquals(1, bundle.getEntry().size()); + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourCtx.newXmlParser().parseResource(Bundle.class, responseContent); + assertEquals(1, bundle.getEntry().size()); - Patient p = BundleUtil.toListOfResourcesOfType(ourCtx, bundle, Patient.class).get(0); - assertEquals(1, p.getName().size()); - assertEquals("Hello", p.getIdElement().getIdPart()); - assertEquals("foo", p.getName().get(0).getFamily()); + Patient p = BundleUtil.toListOfResourcesOfType(ourCtx, bundle, Patient.class).get(0); + assertEquals(1, p.getName().size()); + assertEquals("Hello", p.getIdElement().getIdPart()); + assertEquals("foo-false", p.getName().get(0).getFamily()); + } + } + + @Test + public void testOneIncludeIterate() throws Exception { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?name=Hello&" + Constants.PARAM_INCLUDE_ITERATE + "=foo"); + try (CloseableHttpResponse status = ourClient.execute(httpGet)) { + String responseContent = IOUtils.toString(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourCtx.newXmlParser().parseResource(Bundle.class, responseContent); + assertEquals(1, bundle.getEntry().size()); + + Patient p = BundleUtil.toListOfResourcesOfType(ourCtx, bundle, Patient.class).get(0); + assertEquals(1, p.getName().size()); + assertEquals("Hello", p.getIdElement().getIdPart()); + assertEquals("foo-true", p.getName().get(0).getFamily()); + } } @Test public void testTwoInclude() throws Exception { HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?name=Hello&_include=foo&_include=bar"); - HttpResponse status = ourClient.execute(httpGet); - String responseContent = IOUtils.toString(status.getEntity().getContent()); - IOUtils.closeQuietly(status.getEntity().getContent()); + try (CloseableHttpResponse status = ourClient.execute(httpGet)) { + String responseContent = IOUtils.toString(status.getEntity().getContent()); - assertEquals(200, status.getStatusLine().getStatusCode()); - Bundle bundle = ourCtx.newXmlParser().parseResource(Bundle.class, responseContent); - assertEquals(1, bundle.getEntry().size()); + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourCtx.newXmlParser().parseResource(Bundle.class, responseContent); + assertEquals(1, bundle.getEntry().size()); - Patient p = BundleUtil.toListOfResourcesOfType(ourCtx, bundle, Patient.class).get(0); - assertEquals(2, p.getName().size()); - assertEquals("Hello", p.getIdElement().getIdPart()); + Patient p = BundleUtil.toListOfResourcesOfType(ourCtx, bundle, Patient.class).get(0); + assertEquals(2, p.getName().size()); + assertEquals("Hello", p.getIdElement().getIdPart()); - Set values = new HashSet(); - values.add(p.getName().get(0).getFamily()); - values.add(p.getName().get(1).getFamily()); - assertThat(values, containsInAnyOrder("foo", "bar")); - - } - - - @AfterClass - public static void afterClassClearContext() throws Exception { - JettyUtil.closeServer(ourServer); - TestUtil.clearAllStaticFieldsForUnitTest(); - } - - @BeforeClass - public static void beforeClass() throws Exception { - - ourCtx = FhirContext.forR4(); - ourServer = new Server(0); - - DummyPatientResourceProvider patientProvider = new DummyPatientResourceProvider(); - - ServletHandler proxyHandler = new ServletHandler(); - RestfulServer servlet = new RestfulServer(ourCtx); - servlet.setDefaultResponseEncoding(EncodingEnum.XML); - servlet.setBundleInclusionRule(BundleInclusionRule.BASED_ON_RESOURCE_PRESENCE); - servlet.setResourceProviders(patientProvider, new DummyDiagnosticReportResourceProvider()); - ServletHolder servletHolder = new ServletHolder(servlet); - proxyHandler.addServletWithMapping(servletHolder, "/*"); - ourServer.setHandler(proxyHandler); - JettyUtil.startServer(ourServer); - ourPort = JettyUtil.getPortForStartedServer(ourServer); - - PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS); - HttpClientBuilder builder = HttpClientBuilder.create(); - builder.setConnectionManager(connectionManager); - ourClient = builder.build(); - - } - - public static void main(String[] args) { - - Organization org = new Organization(); - org.setId("Organization/65546"); - org.getNameElement().setValue("Contained Test Organization"); - - Patient patient = new Patient(); - patient.setId("Patient/1333"); - patient.addIdentifier().setSystem("urn:mrns").setValue("253345"); - patient.getManagingOrganization().setResource(patient); - - System.out.println(FhirContext.forR4().newXmlParser().setPrettyPrint(true).encodeResourceToString(patient)); - - patient.getManagingOrganization().getReference(); + Set values = new HashSet(); + values.add(p.getName().get(0).getFamily()); + values.add(p.getName().get(1).getFamily()); + assertThat(values, containsInAnyOrder("foo-false", "bar-false")); + } } /** @@ -397,13 +368,13 @@ public class IncludeTest { Patient p2 = new Patient(); p2.setId("p2"); p2.addIdentifier().setValue("p2"); - p2.addExtension(new org.hl7.fhir.r4.model.Extension( "http://foo", new Reference(o1))); + p2.addExtension(new org.hl7.fhir.r4.model.Extension("http://foo", new Reference(o1))); return Arrays.asList(p1, p2); } @Search - public List findPatientWithSimpleNames(@RequiredParam(name = Patient.SP_NAME) StringDt theName, @IncludeParam(allow = { "foo", "bar" }) Set theIncludes) { + public List findPatientWithSimpleNames(@RequiredParam(name = Patient.SP_NAME) StringDt theName, @IncludeParam(allow = {"foo", "bar"}) Set theIncludes) { ArrayList retVal = new ArrayList<>(); Patient p = new Patient(); @@ -413,7 +384,7 @@ public class IncludeTest { if (theIncludes != null) { for (Include next : theIncludes) { - p.addName().setFamily(next.getValue()); + p.addName().setFamily(next.getValue() + "-" + next.isRecurse()); } } retVal.add(p); @@ -447,11 +418,10 @@ public class IncludeTest { } - @ResourceDef(name = "Patient") public static class ExtPatient extends Patient { private static final long serialVersionUID = 1L; - + @Child(name = "secondOrg") @Extension(url = "http://foo#secondOrg", definedLocally = false, isModifier = false) private Reference mySecondOrg; @@ -470,4 +440,53 @@ public class IncludeTest { } + @AfterClass + public static void afterClassClearContext() throws Exception { + JettyUtil.closeServer(ourServer); + TestUtil.clearAllStaticFieldsForUnitTest(); + } + + @BeforeClass + public static void beforeClass() throws Exception { + + ourCtx = FhirContext.forR4(); + ourServer = new Server(0); + + DummyPatientResourceProvider patientProvider = new DummyPatientResourceProvider(); + + ServletHandler proxyHandler = new ServletHandler(); + RestfulServer servlet = new RestfulServer(ourCtx); + servlet.setDefaultResponseEncoding(EncodingEnum.XML); + servlet.setBundleInclusionRule(BundleInclusionRule.BASED_ON_RESOURCE_PRESENCE); + servlet.setResourceProviders(patientProvider, new DummyDiagnosticReportResourceProvider()); + ServletHolder servletHolder = new ServletHolder(servlet); + proxyHandler.addServletWithMapping(servletHolder, "/*"); + ourServer.setHandler(proxyHandler); + JettyUtil.startServer(ourServer); + ourPort = JettyUtil.getPortForStartedServer(ourServer); + + PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS); + HttpClientBuilder builder = HttpClientBuilder.create(); + builder.setConnectionManager(connectionManager); + ourClient = builder.build(); + + } + + public static void main(String[] args) { + + Organization org = new Organization(); + org.setId("Organization/65546"); + org.getNameElement().setValue("Contained Test Organization"); + + Patient patient = new Patient(); + patient.setId("Patient/1333"); + patient.addIdentifier().setSystem("urn:mrns").setValue("253345"); + patient.getManagingOrganization().setResource(patient); + + System.out.println(FhirContext.forR4().newXmlParser().setPrettyPrint(true).encodeResourceToString(patient)); + + patient.getManagingOrganization().getReference(); + + } + } diff --git a/src/changes/changes.xml b/src/changes/changes.xml index a91dc5d1a65..8c88da54870 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -169,6 +169,14 @@ A NullPointerException when using the AuthorizationInterceptor RuleBuilder to build a conditional rule with a custom tester has been corrected. Thanks to Tue Toft Nørgård for reporting! + + The R4+ client and server modules did not recognize the new + _include:iterate]]> + syntax that replaces the previous + _include:recurse]]> + syntax. Both are now supported on all servers in order to avoid breaking backwards + compatibility, with the new syntax now being emitted in R4+ clients. +