Don't discard _count from parameters when method has @Count

This commit is contained in:
James Agnew 2016-05-13 19:13:39 -04:00
parent 563f4e4c46
commit d5e2170595
6 changed files with 320 additions and 1 deletions

View File

@ -55,7 +55,7 @@ public class CountParameter implements IParameter {
@Override
public Object translateQueryParametersIntoServerArgument(RequestDetails theRequest, BaseMethodBinding<?> theMethodBinding) throws InternalErrorException, InvalidRequestException {
String[] sinceParams = theRequest.getParameters().remove(Constants.PARAM_COUNT);
String[] sinceParams = theRequest.getParameters().get(Constants.PARAM_COUNT);
if (sinceParams != null) {
if (sinceParams.length > 0) {
if (StringUtils.isNotBlank(sinceParams[0])) {

View File

@ -325,6 +325,96 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2SystemTest {
}
/**
* ?identifier=
*/
@Test
public void testTransactionCreateMatchUrlWithOneMatchNoResourceName1() {
String methodName = "testTransactionCreateMatchUrlWithOneMatch";
Bundle request = new Bundle();
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.setId("Patient/" + methodName);
IIdType id = myPatientDao.update(p, mySrd).getId();
ourLog.info("Created patient, got it: {}", id);
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addFamily("Hello");
p.setId("Patient/" + methodName);
request.addEntry().setResource(p).getRequest().setMethod(HTTPVerbEnum.POST).setIfNoneExist("?identifier=urn%3Asystem%7C" + methodName);
Observation o = new Observation();
o.getCode().setText("Some Observation");
o.getSubject().setReference("Patient/" + methodName);
request.addEntry().setResource(o).getRequest().setMethod(HTTPVerbEnum.POST);
Bundle resp = mySystemDao.transaction(mySrd, request);
assertEquals(2, resp.getEntry().size());
Entry respEntry = resp.getEntry().get(0);
assertEquals(Constants.STATUS_HTTP_200_OK + " OK", respEntry.getResponse().getStatus());
assertThat(respEntry.getResponse().getLocation(), endsWith("Patient/" + id.getIdPart() + "/_history/1"));
assertEquals("1", respEntry.getResponse().getEtag());
respEntry = resp.getEntry().get(1);
assertEquals(Constants.STATUS_HTTP_201_CREATED + " Created", respEntry.getResponse().getStatus());
assertThat(respEntry.getResponse().getLocation(), containsString("Observation/"));
assertThat(respEntry.getResponse().getLocation(), endsWith("/_history/1"));
assertEquals("1", respEntry.getResponse().getEtag());
o = (Observation) myObservationDao.read(new IdDt(respEntry.getResponse().getLocationElement()), mySrd);
assertEquals(id.toVersionless(), o.getSubject().getReference());
assertEquals("1", o.getId().getVersionIdPart());
}
/**
* identifier=
*/
@Test
public void testTransactionCreateMatchUrlWithOneMatchNoResourceName2() {
String methodName = "testTransactionCreateMatchUrlWithOneMatch";
Bundle request = new Bundle();
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.setId("Patient/" + methodName);
IIdType id = myPatientDao.update(p, mySrd).getId();
ourLog.info("Created patient, got it: {}", id);
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addFamily("Hello");
p.setId("Patient/" + methodName);
request.addEntry().setResource(p).getRequest().setMethod(HTTPVerbEnum.POST).setIfNoneExist("identifier=urn%3Asystem%7C" + methodName);
Observation o = new Observation();
o.getCode().setText("Some Observation");
o.getSubject().setReference("Patient/" + methodName);
request.addEntry().setResource(o).getRequest().setMethod(HTTPVerbEnum.POST);
Bundle resp = mySystemDao.transaction(mySrd, request);
assertEquals(2, resp.getEntry().size());
Entry respEntry = resp.getEntry().get(0);
assertEquals(Constants.STATUS_HTTP_200_OK + " OK", respEntry.getResponse().getStatus());
assertThat(respEntry.getResponse().getLocation(), endsWith("Patient/" + id.getIdPart() + "/_history/1"));
assertEquals("1", respEntry.getResponse().getEtag());
respEntry = resp.getEntry().get(1);
assertEquals(Constants.STATUS_HTTP_201_CREATED + " Created", respEntry.getResponse().getStatus());
assertThat(respEntry.getResponse().getLocation(), containsString("Observation/"));
assertThat(respEntry.getResponse().getLocation(), endsWith("/_history/1"));
assertEquals("1", respEntry.getResponse().getEtag());
o = (Observation) myObservationDao.read(new IdDt(respEntry.getResponse().getLocationElement()), mySrd);
assertEquals(id.toVersionless(), o.getSubject().getReference());
assertEquals("1", o.getId().getVersionIdPart());
}
@Test
public void testTransactionCreateMatchUrlWithTwoMatch() {
String methodName = "testTransactionCreateMatchUrlWithTwoMatch";

View File

@ -80,6 +80,30 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
TestUtil.clearAllStaticFieldsForUnitTest();
}
@Test
public void testTransactionFromBundle2() throws Exception {
String input = IOUtils.toString(getClass().getResourceAsStream("/transaction-bundle.xml"));
Bundle bundle = myFhirCtx.newXmlParser().parseResource(Bundle.class, input);
Bundle response = mySystemDao.transaction(mySrd, bundle);
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(response));
assertEquals("201 Created", response.getEntryFirstRep().getResponse().getStatus());
assertEquals("Practitioner/1/_history/1", response.getEntryFirstRep().getResponse().getLocation());
/*
* Now a second time
*/
bundle = myFhirCtx.newXmlParser().parseResource(Bundle.class, input);
response = mySystemDao.transaction(mySrd, bundle);
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(response));
assertEquals("200 OK", response.getEntryFirstRep().getResponse().getStatus());
assertEquals("Practitioner/1/_history/1", response.getEntryFirstRep().getResponse().getLocation());
}
@Test
public void testTransactionWithNullReference() {
Patient p = new Patient();

View File

@ -0,0 +1,63 @@
<Bundle xmlns="http://hl7.org/fhir">
<!-- we need to use a transaction for this type of procedure -->
<type value="transaction"/>
<!-- Bundle Id will be generated by Map Force on the client - this is the resource id for the bundle -->
<id value="f9935843-19a2-4a1a-4016-7bea52de77f8"/>
<!--Lets process patient first -->
<!--We still need to include patient in the bundle for our check even though it a cut down bogus entry -->
<entry>
<!--Should this be provided for a Create i.e. should the adapter generate the local id (if resource not exist) or let the fhir server do it? -->
<!--This is generate by Map Force and use for references. If Practitioner does not exist FHIR server should use it at Local Resource Id -->
<fullUrl value="urn:uuid:47709cc7-b3ec-4abc-9d26-3df3d3d57907"/>
<resource>
<Practitioner xmlns="http://hl7.org/fhir">
<identifier>
<use value="official"/>
<!--Reuse value from CDA -->
<system value="urn:oid:2.16.840.1.113883.2.4.6.3"/>
<!--Reuse OIDs from CDA -->
<!-- BSN identification system -->
<value value="567IUI51C157"/>
</identifier>
<name>
<use value="official"/>
<family value="Heps"/>
<given value="Simone"/>
<suffix value="MD"/>
</name>
<telecom>
<system value="phone"/>
<value value="020556936"/>
<use value="work"/>
</telecom>
<telecom>
<system value="email"/>
<value value="S.M.Heps@bmc.nl"/>
<use value="work"/>
</telecom>
<telecom>
<system value="fax"/>
<value value="0205669283"/>
<use value="work"/>
</telecom>
<address>
<use value="work"/>
<line value="Galapagosweg 91"/>
<city value="Den Burg"/>
<postalCode value="9105 PZ"/>
<country value="NLD"/>
<!-- ISO 3166 Codes (Countries) -->
</address>
<gender value="female"/>
<birthDate value="1971-11-07"/>
</Practitioner>
</resource>
<request>
<!--For this entry we only want to create the practitioner based on the entry data if we dont find one -->
<method value="POST"/>
<url value="Practitioner"/>
<!--Use DrProviderNumber Paul to add more syntax below -->
<ifNoneExist value="identifier=567IUI51C157"/>
</request>
</entry>
</Bundle>

View File

@ -0,0 +1,137 @@
package ca.uhn.fhir.rest.server;
import static org.hamcrest.Matchers.stringContainsInOrder;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
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.dstu3.model.HumanName;
import org.hl7.fhir.dstu3.model.Patient;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.annotation.Count;
import ca.uhn.fhir.rest.annotation.OptionalParam;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.util.PortUtil;
import ca.uhn.fhir.util.TestUtil;
public class SearchCountParamDstu3Test {
private static CloseableHttpClient ourClient;
private static FhirContext ourCtx = FhirContext.forDstu3();
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchCountParamDstu3Test.class);
private static int ourPort;
private static Server ourServer;
private static String ourLastMethod;
private static Integer ourLastParam;
@Before
public void before() {
ourLastMethod = null;
ourLastParam = null;
}
@Test
public void testSearch() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_count=2");
CloseableHttpResponse status = ourClient.execute(httpGet);
try {
String responseContent = IOUtils.toString(status.getEntity().getContent());
ourLog.info(responseContent);
assertEquals(200, status.getStatusLine().getStatusCode());
assertEquals("search", ourLastMethod);
assertEquals(new Integer(2), ourLastParam);
//@formatter:off
assertThat(responseContent, stringContainsInOrder(
"<link>",
"<relation value=\"self\"/>",
"<url value=\"http://localhost:" + ourPort + "/Patient?_count=2\"/>",
"</link>",
"<link>",
"<relation value=\"next\"/>",
"<url value=\"http://localhost:" + ourPort + "?_getpages=", "&amp;_getpagesoffset=2&amp;_count=2&amp;_bundletype=searchset\"/>",
"</link>"));
//@formatter:on
} finally {
IOUtils.closeQuietly(status.getEntity().getContent());
}
}
@AfterClass
public static void afterClassClearContext() throws Exception {
ourServer.stop();
TestUtil.clearAllStaticFieldsForUnitTest();
}
@BeforeClass
public static void beforeClass() throws Exception {
ourPort = PortUtil.findFreePort();
ourServer = new Server(ourPort);
DummyPatientResourceProvider patientProvider = new DummyPatientResourceProvider();
ServletHandler proxyHandler = new ServletHandler();
RestfulServer servlet = new RestfulServer(ourCtx);
servlet.setPagingProvider(new FifoMemoryPagingProvider(10));
servlet.setResourceProviders(patientProvider);
ServletHolder servletHolder = new ServletHolder(servlet);
proxyHandler.addServletWithMapping(servletHolder, "/*");
ourServer.setHandler(proxyHandler);
ourServer.start();
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
HttpClientBuilder builder = HttpClientBuilder.create();
builder.setConnectionManager(connectionManager);
ourClient = builder.build();
}
public static class DummyPatientResourceProvider implements IResourceProvider {
@Override
public Class<? extends IBaseResource> getResourceType() {
return Patient.class;
}
//@formatter:off
@SuppressWarnings("rawtypes")
@Search()
public List search(
@OptionalParam(name=Patient.SP_IDENTIFIER) TokenParam theIdentifier,
@Count() Integer theParam
) {
ourLastMethod = "search";
ourLastParam = theParam;
ArrayList<Patient> retVal = new ArrayList<Patient>();
for (int i = 1; i < 100; i++) {
retVal.add((Patient) new Patient().addName(new HumanName().addFamily("FAMILY")).setId("" + i));
}
return retVal;
}
//@formatter:on
}
}

View File

@ -176,6 +176,11 @@
value be completely contained by the range specified. Thanks to Chris Moesel
for the suggestion.
</action>
<action type="fix">
In server, if a parameter was annotated with the <![CDATA[@Count]]> annotation, the
count would not appear in the self/prev/next links and would not actually be applied
to the search results by the server. Thanks to Jim Steele for letting us know!
</action>
</release>
<release version="1.5" date="2016-04-20">
<action type="fix" issue="339">