Fix #1494 - Upgrade to new :recurse syntax for R4 include/revinclude

statements
This commit is contained in:
James Agnew 2019-09-20 09:38:29 -04:00
parent 92d37866de
commit a989a746b0
9 changed files with 248 additions and 201 deletions

View File

@ -40,7 +40,7 @@ public class Include implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private final boolean myImmutable; private final boolean myImmutable;
private boolean myRecurse; private boolean myIterate;
private String myValue; private String myValue;
/** /**
@ -59,12 +59,12 @@ public class Include implements Serializable {
* *
* @param theValue * @param theValue
* The <code>_include</code> value, e.g. "Patient:name" * The <code>_include</code> value, e.g. "Patient:name"
* @param theRecurse * @param theIterate
* Should the include recurse * Should the include recurse
*/ */
public Include(String theValue, boolean theRecurse) { public Include(String theValue, boolean theIterate) {
myValue = theValue; myValue = theValue;
myRecurse = theRecurse; myIterate = theIterate;
myImmutable = false; myImmutable = false;
} }
@ -73,12 +73,12 @@ public class Include implements Serializable {
* *
* @param theValue * @param theValue
* The <code>_include</code> value, e.g. "Patient:name" * The <code>_include</code> value, e.g. "Patient:name"
* @param theRecurse * @param theIterate
* Should the include recurse * Should the include recurse
*/ */
public Include(String theValue, boolean theRecurse, boolean theImmutable) { public Include(String theValue, boolean theIterate, boolean theImmutable) {
myValue = theValue; myValue = theValue;
myRecurse = theRecurse; myIterate = theIterate;
myImmutable = theImmutable; myImmutable = theImmutable;
} }
@ -111,7 +111,7 @@ public class Include implements Serializable {
return false; return false;
} }
Include other = (Include) obj; Include other = (Include) obj;
if (myRecurse != other.myRecurse) { if (myIterate != other.myIterate) {
return false; return false;
} }
if (myValue == null) { if (myValue == null) {
@ -177,7 +177,7 @@ public class Include implements Serializable {
public int hashCode() { public int hashCode() {
final int prime = 31; final int prime = 31;
int result = 1; int result = 1;
result = prime * result + (myRecurse ? 1231 : 1237); result = prime * result + (myIterate ? 1231 : 1237);
result = prime * result + ((myValue == null) ? 0 : myValue.hashCode()); result = prime * result + ((myValue == null) ? 0 : myValue.hashCode());
return result; return result;
} }
@ -190,7 +190,7 @@ public class Include implements Serializable {
} }
public boolean isRecurse() { public boolean isRecurse() {
return myRecurse; return myIterate;
} }
/** /**
@ -199,7 +199,7 @@ public class Include implements Serializable {
* @return Returns a reference to <code>this</code> for easy method chaining * @return Returns a reference to <code>this</code> for easy method chaining
*/ */
public Include setRecurse(boolean theRecurse) { public Include setRecurse(boolean theRecurse) {
myRecurse = theRecurse; myIterate = theRecurse;
return this; return this;
} }
@ -214,7 +214,7 @@ public class Include implements Serializable {
* Return a new * Return a new
*/ */
public Include toLocked() { public Include toLocked() {
Include retVal = new Include(myValue, myRecurse, true); Include retVal = new Include(myValue, myIterate, true);
return retVal; return retVal;
} }
@ -222,7 +222,7 @@ public class Include implements Serializable {
public String toString() { public String toString() {
ToStringBuilder builder = new ToStringBuilder(this); ToStringBuilder builder = new ToStringBuilder(this);
builder.append("value", myValue); builder.append("value", myValue);
builder.append("recurse", myRecurse); builder.append("iterate", myIterate);
return builder.toString(); return builder.toString();
} }
@ -273,7 +273,7 @@ public class Include implements Serializable {
b.append(':'); b.append(':');
b.append(theResourceType); b.append(theResourceType);
} }
Include retVal = new Include(b.toString(), myRecurse, myImmutable); Include retVal = new Include(b.toString(), myIterate, myImmutable);
return retVal; return retVal;
} }

View File

@ -151,6 +151,8 @@ public class Constants {
public static final String PARAM_INCLUDE = "_include"; public static final String PARAM_INCLUDE = "_include";
public static final String PARAM_INCLUDE_QUALIFIER_RECURSE = ":recurse"; 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_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_LASTUPDATED = "_lastUpdated";
public static final String PARAM_NARRATIVE = "_narrative"; public static final String PARAM_NARRATIVE = "_narrative";
public static final String PARAM_PAGINGACTION = "_getpages"; 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_RESPONSE_URL = "response-url"; //Used in messaging
public static final String PARAM_REVINCLUDE = "_revinclude"; 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_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_SEARCH = "_search";
public static final String PARAM_SECURITY = "_security"; public static final String PARAM_SECURITY = "_security";
public static final String PARAM_SINCE = "_since"; public static final String PARAM_SINCE = "_since";

View File

@ -1761,7 +1761,11 @@ public class GenericClient extends BaseClient implements IGenericClient {
for (Include next : myInclude) { for (Include next : myInclude) {
if (next.isRecurse()) { 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 { } else {
addParam(params, Constants.PARAM_INCLUDE, next.getValue()); addParam(params, Constants.PARAM_INCLUDE, next.getValue());
} }
@ -1769,7 +1773,11 @@ public class GenericClient extends BaseClient implements IGenericClient {
for (Include next : myRevInclude) { for (Include next : myRevInclude) {
if (next.isRecurse()) { 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 { } else {
addParam(params, Constants.PARAM_REVINCLUDE, next.getValue()); addParam(params, Constants.PARAM_REVINCLUDE, next.getValue());
} }

View File

@ -23,6 +23,7 @@ import java.util.*;
import ca.uhn.fhir.context.ConfigurationException; import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.model.api.Include; import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.rest.annotation.IncludeParam; import ca.uhn.fhir.rest.annotation.IncludeParam;
import ca.uhn.fhir.rest.api.*; import ca.uhn.fhir.rest.api.*;
@ -64,23 +65,30 @@ class IncludeParameter extends BaseQueryParameter {
if (myInstantiableCollectionType == null) { if (myInstantiableCollectionType == null) {
if (mySpecType == Include.class) { if (mySpecType == Include.class) {
convertAndAddIncludeToList(retVal, (Include) theObject); convertAndAddIncludeToList(retVal, (Include) theObject, theContext);
} else { } else {
retVal.add(QualifiedParamList.singleton(((String) theObject))); retVal.add(QualifiedParamList.singleton(((String) theObject)));
} }
} else { } else {
Collection<Include> val = (Collection<Include>) theObject; Collection<Include> val = (Collection<Include>) theObject;
for (Include include : val) { for (Include include : val) {
convertAndAddIncludeToList(retVal, include); convertAndAddIncludeToList(retVal, include, theContext);
} }
} }
return retVal; return retVal;
} }
private void convertAndAddIncludeToList(ArrayList<QualifiedParamList> retVal, Include include) { private void convertAndAddIncludeToList(ArrayList<QualifiedParamList> theQualifiedParamLists, Include theInclude, FhirContext theContext) {
String qualifier = include.isRecurse() ? Constants.PARAM_INCLUDE_QUALIFIER_RECURSE : null; String qualifier = null;
retVal.add(QualifiedParamList.singleton(qualifier, include.getValue())); 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<String> getAllow() { public Set<String> getAllow() {

View File

@ -136,7 +136,8 @@ class IncludeParameter extends BaseQueryParameter {
throw new InvalidRequestException(theContext.getLocalizer().getMessage(IncludeParameter.class, "orIncludeInRequest")); 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); String value = nextParamList.get(0);
if (myAllow != null && !myAllow.isEmpty()) { if (myAllow != null && !myAllow.isEmpty()) {

View File

@ -924,7 +924,7 @@ public class ClientR4Test {
ITestClient client = ourCtx.newRestfulClient(ITestClient.class, "http://foo"); 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)})); 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());
} }

View File

@ -1451,7 +1451,7 @@ public class GenericClientR4Test {
.returnBundle(Bundle.class) .returnBundle(Bundle.class)
.execute(); .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()); capt.getAllValues().get(idx).getURI().toString());
idx++; idx++;

View File

@ -1,28 +1,5 @@
package ca.uhn.fhir.rest.server; 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.FhirContext;
import ca.uhn.fhir.context.api.BundleInclusionRule; import ca.uhn.fhir.context.api.BundleInclusionRule;
import ca.uhn.fhir.model.api.Include; 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.Extension;
import ca.uhn.fhir.model.api.annotation.ResourceDef; import ca.uhn.fhir.model.api.annotation.ResourceDef;
import ca.uhn.fhir.model.primitive.StringDt; import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.rest.annotation.*; import ca.uhn.fhir.rest.annotation.IncludeParam;
import ca.uhn.fhir.util.*; 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 { public class IncludeTest {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(IncludeTest.class);
private static CloseableHttpClient ourClient; private static CloseableHttpClient ourClient;
private static FhirContext ourCtx; private static FhirContext ourCtx;
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(IncludeTest.class);
private static int ourPort; private static int ourPort;
private static Server ourServer; private static Server ourServer;
@Test @Test
public void testBadInclude() throws Exception { public void testBadInclude() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?name=Hello&_include=foo&_include=baz"); HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?name=Hello&_include=foo&_include=baz");
HttpResponse status = ourClient.execute(httpGet); try (CloseableHttpResponse status = ourClient.execute(httpGet)) {
assertEquals(400, status.getStatusLine().getStatusCode()); assertEquals(400, status.getStatusLine().getStatusCode());
String responseContent = IOUtils.toString(status.getEntity().getContent()); String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
ourLog.info(responseContent); ourLog.info(responseContent);
assertThat(responseContent, containsString("Invalid _include parameter value")); assertThat(responseContent, containsString("Invalid _include parameter value"));
}
} }
@Test @Test
public void testIIncludedResourcesNonContained() throws Exception { public void testIIncludedResourcesNonContained() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=normalInclude&_pretty=true"); HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=normalInclude&_pretty=true");
HttpResponse status = ourClient.execute(httpGet); try (CloseableHttpResponse status = ourClient.execute(httpGet)) {
String responseContent = IOUtils.toString(status.getEntity().getContent()); String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
assertEquals(200, status.getStatusLine().getStatusCode()); assertEquals(200, status.getStatusLine().getStatusCode());
Bundle bundle = ourCtx.newXmlParser().parseResource(Bundle.class, responseContent); Bundle bundle = ourCtx.newXmlParser().parseResource(Bundle.class, responseContent);
ourLog.info(responseContent); ourLog.info(responseContent);
assertEquals(3, bundle.getEntry().size()); assertEquals(3, bundle.getEntry().size());
assertEquals(("Patient/p1"), bundle.getEntry().get(0).getResource().getIdElement().toUnqualifiedVersionless().getValue()); assertEquals(("Patient/p1"), bundle.getEntry().get(0).getResource().getIdElement().toUnqualifiedVersionless().getValue());
assertEquals(("Patient/p2"), bundle.getEntry().get(1).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/o1"), bundle.getEntry().get(2).getResource().getIdElement().toUnqualifiedVersionless().getValue());
Patient p1 = (Patient) bundle.getEntry().get(0).getResource(); Patient p1 = (Patient) bundle.getEntry().get(0).getResource();
assertEquals(0, p1.getContained().size()); assertEquals(0, p1.getContained().size());
Patient p2 = (Patient) bundle.getEntry().get(1).getResource(); Patient p2 = (Patient) bundle.getEntry().get(1).getResource();
assertEquals(0, p2.getContained().size()); assertEquals(0, p2.getContained().size());
}
} }
@Test @Test
public void testIIncludedResourcesNonContainedInDeclaredExtension() throws Exception { public void testIIncludedResourcesNonContainedInDeclaredExtension() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=declaredExtInclude&_pretty=true"); HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=declaredExtInclude&_pretty=true");
HttpResponse status = ourClient.execute(httpGet); try (CloseableHttpResponse status = ourClient.execute(httpGet)) {
String responseContent = IOUtils.toString(status.getEntity().getContent()); String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
assertEquals(200, status.getStatusLine().getStatusCode()); assertEquals(200, status.getStatusLine().getStatusCode());
Bundle bundle = ourCtx.newXmlParser().parseResource(Bundle.class, responseContent); Bundle bundle = ourCtx.newXmlParser().parseResource(Bundle.class, responseContent);
ourLog.info(responseContent); ourLog.info(responseContent);
assertEquals(4, bundle.getEntry().size()); assertEquals(4, bundle.getEntry().size());
assertEquals(("Patient/p1"), bundle.getEntry().get(0).getResource().getIdElement().toUnqualifiedVersionless().getValue()); assertEquals(("Patient/p1"), bundle.getEntry().get(0).getResource().getIdElement().toUnqualifiedVersionless().getValue());
assertEquals(("Patient/p2"), bundle.getEntry().get(1).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/o1"), bundle.getEntry().get(2).getResource().getIdElement().toUnqualifiedVersionless().getValue());
assertEquals(("Organization/o2"), bundle.getEntry().get(3).getResource().getIdElement().toUnqualifiedVersionless().getValue()); assertEquals(("Organization/o2"), bundle.getEntry().get(3).getResource().getIdElement().toUnqualifiedVersionless().getValue());
Patient p1 = (Patient) bundle.getEntry().get(0).getResource(); Patient p1 = (Patient) bundle.getEntry().get(0).getResource();
assertEquals(0, p1.getContained().size()); assertEquals(0, p1.getContained().size());
Patient p2 = (Patient) bundle.getEntry().get(1).getResource(); Patient p2 = (Patient) bundle.getEntry().get(1).getResource();
assertEquals(0, p2.getContained().size()); assertEquals(0, p2.getContained().size());
}
} }
@Test @Test
public void testIIncludedResourcesNonContainedInExtension() throws Exception { public void testIIncludedResourcesNonContainedInExtension() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=extInclude&_pretty=true"); HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=extInclude&_pretty=true");
HttpResponse status = ourClient.execute(httpGet); try (CloseableHttpResponse status = ourClient.execute(httpGet)) {
String responseContent = IOUtils.toString(status.getEntity().getContent()); String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
assertEquals(200, status.getStatusLine().getStatusCode()); assertEquals(200, status.getStatusLine().getStatusCode());
Bundle bundle = ourCtx.newXmlParser().parseResource(Bundle.class, responseContent); Bundle bundle = ourCtx.newXmlParser().parseResource(Bundle.class, responseContent);
ourLog.info(responseContent); ourLog.info(responseContent);
assertEquals(3, bundle.getEntry().size()); assertEquals(3, bundle.getEntry().size());
assertEquals(("Patient/p1"), bundle.getEntry().get(0).getResource().getIdElement().toUnqualifiedVersionless().getValue()); assertEquals(("Patient/p1"), bundle.getEntry().get(0).getResource().getIdElement().toUnqualifiedVersionless().getValue());
assertEquals(("Patient/p2"), bundle.getEntry().get(1).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/o1"), bundle.getEntry().get(2).getResource().getIdElement().toUnqualifiedVersionless().getValue());
Patient p1 = (Patient) bundle.getEntry().get(0).getResource(); Patient p1 = (Patient) bundle.getEntry().get(0).getResource();
assertEquals(0, p1.getContained().size()); assertEquals(0, p1.getContained().size());
Patient p2 = (Patient) bundle.getEntry().get(1).getResource(); Patient p2 = (Patient) bundle.getEntry().get(1).getResource();
assertEquals(0, p2.getContained().size()); assertEquals(0, p2.getContained().size());
}
} }
@Test @Test
public void testIIncludedResourcesNonContainedInExtensionJson() throws Exception { public void testIIncludedResourcesNonContainedInExtensionJson() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=extInclude&_pretty=true&_format=json"); HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=extInclude&_pretty=true&_format=json");
HttpResponse status = ourClient.execute(httpGet); try (CloseableHttpResponse status = ourClient.execute(httpGet)) {
String responseContent = IOUtils.toString(status.getEntity().getContent()); String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
assertEquals(200, status.getStatusLine().getStatusCode()); assertEquals(200, status.getStatusLine().getStatusCode());
Bundle bundle = ourCtx.newJsonParser().parseResource(Bundle.class, responseContent); Bundle bundle = ourCtx.newJsonParser().parseResource(Bundle.class, responseContent);
ourLog.info(responseContent); ourLog.info(responseContent);
assertEquals(3, bundle.getEntry().size()); assertEquals(3, bundle.getEntry().size());
assertEquals("Patient/p1", bundle.getEntry().get(0).getResource().getIdElement().toUnqualifiedVersionless().getValue()); assertEquals("Patient/p1", bundle.getEntry().get(0).getResource().getIdElement().toUnqualifiedVersionless().getValue());
assertEquals("Patient/p2", bundle.getEntry().get(1).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/o1", bundle.getEntry().get(2).getResource().getIdElement().toUnqualifiedVersionless().getValue());
Patient p1 = (Patient) bundle.getEntry().get(0).getResource(); Patient p1 = (Patient) bundle.getEntry().get(0).getResource();
assertEquals(0, p1.getContained().size()); assertEquals(0, p1.getContained().size());
Patient p2 = (Patient) bundle.getEntry().get(1).getResource(); Patient p2 = (Patient) bundle.getEntry().get(1).getResource();
assertEquals(0, p2.getContained().size()); assertEquals(0, p2.getContained().size());
}
} }
@Test @Test
@ -189,106 +193,73 @@ public class IncludeTest {
@Test @Test
public void testNoIncludes() throws Exception { public void testNoIncludes() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?name=Hello"); HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?name=Hello");
HttpResponse status = ourClient.execute(httpGet); try (CloseableHttpResponse status = ourClient.execute(httpGet)) {
String responseContent = IOUtils.toString(status.getEntity().getContent()); String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
assertEquals(200, status.getStatusLine().getStatusCode()); assertEquals(200, status.getStatusLine().getStatusCode());
Bundle bundle = ourCtx.newXmlParser().parseResource(Bundle.class, responseContent); Bundle bundle = ourCtx.newXmlParser().parseResource(Bundle.class, responseContent);
assertEquals(1, bundle.getEntry().size()); assertEquals(1, bundle.getEntry().size());
Patient p = BundleUtil.toListOfResourcesOfType(ourCtx, bundle, Patient.class).get(0); Patient p = BundleUtil.toListOfResourcesOfType(ourCtx, bundle, Patient.class).get(0);
assertEquals(0, p.getName().size()); assertEquals(0, p.getName().size());
assertEquals("Hello", p.getIdElement().getIdPart()); assertEquals("Hello", p.getIdElement().getIdPart());
}
} }
@Test @Test
public void testOneInclude() throws Exception { public void testOneInclude() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?name=Hello&_include=foo"); HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?name=Hello&_include=foo");
HttpResponse status = ourClient.execute(httpGet); try (CloseableHttpResponse status = ourClient.execute(httpGet)) {
String responseContent = IOUtils.toString(status.getEntity().getContent()); String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
assertEquals(200, status.getStatusLine().getStatusCode()); assertEquals(200, status.getStatusLine().getStatusCode());
Bundle bundle = ourCtx.newXmlParser().parseResource(Bundle.class, responseContent); Bundle bundle = ourCtx.newXmlParser().parseResource(Bundle.class, responseContent);
assertEquals(1, bundle.getEntry().size()); assertEquals(1, bundle.getEntry().size());
Patient p = BundleUtil.toListOfResourcesOfType(ourCtx, bundle, Patient.class).get(0); Patient p = BundleUtil.toListOfResourcesOfType(ourCtx, bundle, Patient.class).get(0);
assertEquals(1, p.getName().size()); assertEquals(1, p.getName().size());
assertEquals("Hello", p.getIdElement().getIdPart()); assertEquals("Hello", p.getIdElement().getIdPart());
assertEquals("foo", p.getName().get(0).getFamily()); 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 @Test
public void testTwoInclude() throws Exception { public void testTwoInclude() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?name=Hello&_include=foo&_include=bar"); HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?name=Hello&_include=foo&_include=bar");
HttpResponse status = ourClient.execute(httpGet); try (CloseableHttpResponse status = ourClient.execute(httpGet)) {
String responseContent = IOUtils.toString(status.getEntity().getContent()); String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
assertEquals(200, status.getStatusLine().getStatusCode()); assertEquals(200, status.getStatusLine().getStatusCode());
Bundle bundle = ourCtx.newXmlParser().parseResource(Bundle.class, responseContent); Bundle bundle = ourCtx.newXmlParser().parseResource(Bundle.class, responseContent);
assertEquals(1, bundle.getEntry().size()); assertEquals(1, bundle.getEntry().size());
Patient p = BundleUtil.toListOfResourcesOfType(ourCtx, bundle, Patient.class).get(0); Patient p = BundleUtil.toListOfResourcesOfType(ourCtx, bundle, Patient.class).get(0);
assertEquals(2, p.getName().size()); assertEquals(2, p.getName().size());
assertEquals("Hello", p.getIdElement().getIdPart()); assertEquals("Hello", p.getIdElement().getIdPart());
Set<String> values = new HashSet<String>(); Set<String> values = new HashSet<String>();
values.add(p.getName().get(0).getFamily()); values.add(p.getName().get(0).getFamily());
values.add(p.getName().get(1).getFamily()); values.add(p.getName().get(1).getFamily());
assertThat(values, containsInAnyOrder("foo", "bar")); assertThat(values, containsInAnyOrder("foo-false", "bar-false"));
}
@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();
}
} }
/** /**
@ -397,13 +368,13 @@ public class IncludeTest {
Patient p2 = new Patient(); Patient p2 = new Patient();
p2.setId("p2"); p2.setId("p2");
p2.addIdentifier().setValue("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); return Arrays.asList(p1, p2);
} }
@Search @Search
public List<Patient> findPatientWithSimpleNames(@RequiredParam(name = Patient.SP_NAME) StringDt theName, @IncludeParam(allow = { "foo", "bar" }) Set<Include> theIncludes) { public List<Patient> findPatientWithSimpleNames(@RequiredParam(name = Patient.SP_NAME) StringDt theName, @IncludeParam(allow = {"foo", "bar"}) Set<Include> theIncludes) {
ArrayList<Patient> retVal = new ArrayList<>(); ArrayList<Patient> retVal = new ArrayList<>();
Patient p = new Patient(); Patient p = new Patient();
@ -413,7 +384,7 @@ public class IncludeTest {
if (theIncludes != null) { if (theIncludes != null) {
for (Include next : theIncludes) { for (Include next : theIncludes) {
p.addName().setFamily(next.getValue()); p.addName().setFamily(next.getValue() + "-" + next.isRecurse());
} }
} }
retVal.add(p); retVal.add(p);
@ -447,7 +418,6 @@ public class IncludeTest {
} }
@ResourceDef(name = "Patient") @ResourceDef(name = "Patient")
public static class ExtPatient extends Patient { public static class ExtPatient extends Patient {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@ -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();
}
} }

View File

@ -169,6 +169,14 @@
A NullPointerException when using the AuthorizationInterceptor RuleBuilder to build a conditional 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! rule with a custom tester has been corrected. Thanks to Tue Toft Nørgård for reporting!
</action> </action>
<action type="fix" issue="1494">
The R4+ client and server modules did not recognize the new
<![CDATA[<code>_include:iterate</code>]]>
syntax that replaces the previous
<![CDATA[<code>_include:recurse</code>]]>
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.
</action>
</release> </release>
<release version="4.0.3" date="2019-09-03" description="Igloo (Point Release)"> <release version="4.0.3" date="2019-09-03" description="Igloo (Point Release)">
<action type="fix"> <action type="fix">