diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/ConditionalParamBinder.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/ConditionalParamBinder.java
index 1d96e2c88e6..1a418009522 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/ConditionalParamBinder.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/ConditionalParamBinder.java
@@ -83,16 +83,6 @@ class ConditionalParamBinder implements IParameter {
if (theRequest.getId() != null && theRequest.getId().hasIdPart()) {
return null;
}
- boolean haveParam = false;
- for (String next : theRequest.getParameters().keySet()) {
- if (!next.startsWith("_")) {
- haveParam=true;
- break;
- }
- }
- if (!haveParam) {
- return null;
- }
int questionMarkIndex = theRequest.getCompleteUrl().indexOf('?');
return theRequest.getResourceName() + theRequest.getCompleteUrl().substring(questionMarkIndex);
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirSystemDaoDstu3Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirSystemDaoDstu3Test.java
index d0639250319..8f8d304265c 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirSystemDaoDstu3Test.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirSystemDaoDstu3Test.java
@@ -528,6 +528,40 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
}
+ @Test
+ public void testTransactionCreateInlineMatchUrlWithOneMatchLastUpdated() {
+ Bundle request = new Bundle();
+ Observation o = new Observation();
+ o.getCode().setText("Some Observation");
+ request.addEntry().setResource(o).getRequest().setMethod(HTTPVerb.POST).setIfNoneExist("Observation?_lastUpdated=gt2011-01-01");
+ Bundle resp = mySystemDao.transaction(mySrd, request);
+ assertEquals(1, resp.getEntry().size());
+
+ BundleEntryComponent respEntry = resp.getEntry().get(0);
+ 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());
+
+ /*
+ * Second time should not update
+ */
+
+ request = new Bundle();
+ o = new Observation();
+ o.getCode().setText("Some Observation");
+ request.addEntry().setResource(o).getRequest().setMethod(HTTPVerb.POST).setIfNoneExist("Observation?_lastUpdated=gt2011-01-01");
+ resp = mySystemDao.transaction(mySrd, request);
+ assertEquals(1, resp.getEntry().size());
+
+ respEntry = resp.getEntry().get(0);
+ assertEquals(Constants.STATUS_HTTP_200_OK + " OK", respEntry.getResponse().getStatus());
+ assertThat(respEntry.getResponse().getLocation(), containsString("Observation/"));
+ assertThat(respEntry.getResponse().getLocation(), endsWith("/_history/1"));
+ assertEquals("1", respEntry.getResponse().getEtag());
+
+ }
+
@Test
public void testTransactionCreateInlineMatchUrlWithNoMatches() {
String methodName = "testTransactionCreateInlineMatchUrlWithNoMatches";
diff --git a/hapi-fhir-jpaserver-base/src/test/resources/transaction-bundle2.xml b/hapi-fhir-jpaserver-base/src/test/resources/transaction-bundle2.xml
new file mode 100644
index 00000000000..1837ad4fbde
--- /dev/null
+++ b/hapi-fhir-jpaserver-base/src/test/resources/transaction-bundle2.xml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/rest/server/CreateDstu3Test.java b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/rest/server/CreateDstu3Test.java
index d4e09dc8a97..af26f5a3aab 100644
--- a/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/rest/server/CreateDstu3Test.java
+++ b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/rest/server/CreateDstu3Test.java
@@ -31,6 +31,7 @@ import org.junit.BeforeClass;
import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.rest.annotation.ConditionalUrlParam;
import ca.uhn.fhir.rest.annotation.Create;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Read;
@@ -49,33 +50,6 @@ public class CreateDstu3Test {
private static int ourPort;
private static Server ourServer;
- @Test
- public void testRead() throws Exception {
-
- HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/2?_format=xml&_pretty=true");
- HttpResponse status = ourClient.execute(httpGet);
-
- String responseContent = IOUtils.toString(status.getEntity().getContent());
- IOUtils.closeQuietly(status.getEntity().getContent());
-
- ourLog.info("Response was:\n{}", responseContent);
-
- assertEquals(200, status.getStatusLine().getStatusCode());
-
- //@formatter:off
- assertThat(responseContent, stringContainsInOrder(
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- ""));
- //@formatter:on
- }
-
/**
* #342
*/
@@ -93,7 +67,34 @@ public class CreateDstu3Test {
assertEquals(400, status.getStatusLine().getStatusCode());
String expected = "
";
assertEquals(expected, responseContent);
-
+
+ }
+
+ @Test
+ public void testRead() throws Exception {
+
+ HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/2?_format=xml&_pretty=true");
+ HttpResponse status = ourClient.execute(httpGet);
+
+ String responseContent = IOUtils.toString(status.getEntity().getContent());
+ IOUtils.closeQuietly(status.getEntity().getContent());
+
+ ourLog.info("Response was:\n{}", responseContent);
+
+ assertEquals(200, status.getStatusLine().getStatusCode());
+
+ //@formatter:off
+ assertThat(responseContent, stringContainsInOrder(
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ ""));
+ //@formatter:on
}
@Test
@@ -108,7 +109,7 @@ public class CreateDstu3Test {
ourLog.info("Response was:\n{}", responseContent);
assertEquals(200, status.getStatusLine().getStatusCode());
-
+
//@formatter:off
assertThat(responseContent, stringContainsInOrder(
"",
@@ -121,7 +122,7 @@ public class CreateDstu3Test {
"",
""));
//@formatter:on
-
+
assertThat(responseContent, not(containsString("http://hl7.org/fhir/")));
}
@@ -156,6 +157,11 @@ public class CreateDstu3Test {
public static class PatientProvider implements IResourceProvider {
+ @Create()
+ public MethodOutcome create(@ResourceParam Patient theIdParam) {
+ return new MethodOutcome(new IdType("Patient", "1"), true);
+ }
+
@Override
public Class getResourceType() {
return Patient.class;
@@ -169,11 +175,6 @@ public class CreateDstu3Test {
return p0;
}
- @Create()
- public MethodOutcome read(@ResourceParam Patient theIdParam) {
- return new MethodOutcome(new IdType("Patient", "1"), true);
- }
-
@Search
public List search() {
ArrayList retVal = new ArrayList();
diff --git a/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/rest/server/UpdateDstu3Test.java b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/rest/server/UpdateDstu3Test.java
index 4c0fc590657..7a80fdf028f 100644
--- a/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/rest/server/UpdateDstu3Test.java
+++ b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/rest/server/UpdateDstu3Test.java
@@ -6,6 +6,7 @@ import java.util.concurrent.TimeUnit;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
@@ -19,11 +20,13 @@ import org.hl7.fhir.dstu3.model.IdType;
import org.hl7.fhir.dstu3.model.OperationOutcome;
import org.hl7.fhir.dstu3.model.Patient;
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.model.primitive.IdDt;
+import ca.uhn.fhir.rest.annotation.ConditionalUrlParam;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.ResourceParam;
import ca.uhn.fhir.rest.annotation.Update;
@@ -63,6 +66,53 @@ public class UpdateDstu3Test {
}
+ @Test
+ public void testUpdateConditional() throws Exception {
+
+ Patient patient = new Patient();
+ patient.setId("001");
+ patient.addIdentifier().setValue("002");
+
+ HttpPut httpPost = new HttpPut("http://localhost:" + ourPort + "/Patient?_id=001");
+ httpPost.setEntity(new StringEntity(ourCtx.newXmlParser().encodeResourceToString(patient), ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
+
+ CloseableHttpResponse status = ourClient.execute(httpPost);
+ try {
+ String responseContent = IOUtils.toString(status.getEntity().getContent());
+ ourLog.info("Response was:\n{}", responseContent);
+ assertEquals(200, status.getStatusLine().getStatusCode());
+
+ assertEquals("Patient?_id=001",ourConditionalUrl);
+ assertEquals(null, ourId);
+ } finally {
+ IOUtils.closeQuietly(status.getEntity().getContent());
+ }
+
+ }
+
+ @Test
+ public void testUpdateNormal() throws Exception {
+
+ Patient patient = new Patient();
+ patient.addIdentifier().setValue("002");
+
+ HttpPut httpPost = new HttpPut("http://localhost:" + ourPort + "/Patient/001");
+ httpPost.setEntity(new StringEntity(ourCtx.newXmlParser().encodeResourceToString(patient), ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
+
+ CloseableHttpResponse status = ourClient.execute(httpPost);
+ try {
+ String responseContent = IOUtils.toString(status.getEntity().getContent());
+ ourLog.info("Response was:\n{}", responseContent);
+ assertEquals(200, status.getStatusLine().getStatusCode());
+
+ assertNull(ourConditionalUrl);
+ assertEquals("Patient/001", ourId.getValue());
+ } finally {
+ IOUtils.closeQuietly(status.getEntity().getContent());
+ }
+
+ }
+
@Test
public void testUpdateWrongUrlInBody() throws Exception {
@@ -81,7 +131,9 @@ public class UpdateDstu3Test {
ourLog.info("Response was:\n{}", responseContent);
OperationOutcome oo = ourCtx.newXmlParser().parseResource(OperationOutcome.class, responseContent);
- assertEquals("Can not update resource, resource body must contain an ID element which matches the request URL for update (PUT) operation - Resource body ID of \"3\" does not match URL ID of \"001\"", oo.getIssueFirstRep().getDiagnostics());
+ assertEquals(
+ "Can not update resource, resource body must contain an ID element which matches the request URL for update (PUT) operation - Resource body ID of \"3\" does not match URL ID of \"001\"",
+ oo.getIssueFirstRep().getDiagnostics());
assertEquals(400, status.getStatusLine().getStatusCode());
assertNull(status.getFirstHeader("location"));
@@ -115,7 +167,15 @@ public class UpdateDstu3Test {
}
+ private static String ourConditionalUrl;
+ @Before
+ public void before() {
+ ourConditionalUrl = null;
+ ourId = null;
+ }
+
+ private static IdType ourId;
public static class PatientProvider implements IResourceProvider {
@@ -125,11 +185,13 @@ public class UpdateDstu3Test {
}
@Update()
- public MethodOutcome updatePatient(@IdParam IdType theId, @ResourceParam Patient thePatient) {
- IdType id = theId.withVersion(thePatient.getIdentifierFirstRep().getValue());
+ public MethodOutcome updatePatient(@IdParam IdType theId, @ResourceParam Patient thePatient, @ConditionalUrlParam String theConditionalUrl) {
+ ourId = theId;
+ ourConditionalUrl = theConditionalUrl;
+ IdType id = theId != null ? theId.withVersion(thePatient.getIdentifierFirstRep().getValue()) : new IdType("Patient/1");
OperationOutcome oo = new OperationOutcome();
oo.addIssue().setDiagnostics("OODETAILS");
- if (theId.getValueAsString().contains("CREATE")) {
+ if (id.getValueAsString().contains("CREATE")) {
return new MethodOutcome(id, oo, true);
}
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 8269dcb7647..c209c3d3c09 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -181,6 +181,11 @@
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!
+
+ Conditional update on server failed to process if the conditional URL did not have any
+ search parameters that did not start with an underscore. E.g. "Patient?_id=1" failed
+ even though this is a valid conditional reference.
+