Correctly process ifMatch in Bundle entries for JPA server transaction

This commit is contained in:
James Agnew 2017-10-11 13:00:37 -04:00
parent 78b7188fbc
commit 9b31741147
7 changed files with 252 additions and 2 deletions

View File

@ -29,6 +29,7 @@ import java.util.Map.Entry;
import javax.persistence.TypedQuery; import javax.persistence.TypedQuery;
import ca.uhn.fhir.jpa.util.StopWatch; import ca.uhn.fhir.jpa.util.StopWatch;
import ca.uhn.fhir.rest.param.ParameterUtil;
import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.Validate;
import org.apache.http.NameValuePair; import org.apache.http.NameValuePair;
import org.hibernate.Session; import org.hibernate.Session;
@ -438,7 +439,11 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
DaoMethodOutcome outcome; DaoMethodOutcome outcome;
UrlParts parts = UrlUtil.parseUrl(url); UrlParts parts = UrlUtil.parseUrl(url);
if (isNotBlank(parts.getResourceId())) { if (isNotBlank(parts.getResourceId())) {
res.setId(new IdType(parts.getResourceType(), parts.getResourceId())); String version = null;
if (isNotBlank(nextReqEntry.getRequest().getIfMatch())) {
version = ParameterUtil.parseETagValue(nextReqEntry.getRequest().getIfMatch());
}
res.setId(new IdType(parts.getResourceType(), parts.getResourceId(), version));
outcome = resourceDao.update(res, null, false, theRequestDetails); outcome = resourceDao.update(res, null, false, theRequestDetails);
} else { } else {
res.setId((String) null); res.setId((String) null);

View File

@ -28,6 +28,7 @@ import java.util.Map.Entry;
import javax.persistence.TypedQuery; import javax.persistence.TypedQuery;
import ca.uhn.fhir.rest.param.ParameterUtil;
import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.Validate;
import org.apache.http.NameValuePair; import org.apache.http.NameValuePair;
import org.hl7.fhir.r4.model.*; import org.hl7.fhir.r4.model.*;
@ -435,7 +436,11 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao<Bundle, Meta> {
DaoMethodOutcome outcome; DaoMethodOutcome outcome;
UrlParts parts = UrlUtil.parseUrl(url); UrlParts parts = UrlUtil.parseUrl(url);
if (isNotBlank(parts.getResourceId())) { if (isNotBlank(parts.getResourceId())) {
res.setId(new IdType(parts.getResourceType(), parts.getResourceId())); String version = null;
if (isNotBlank(nextReqEntry.getRequest().getIfMatch())) {
version = ParameterUtil.parseETagValue(nextReqEntry.getRequest().getIfMatch());
}
res.setId(new IdType(parts.getResourceType(), parts.getResourceId(), version));
outcome = resourceDao.update(res, null, false, theRequestDetails); outcome = resourceDao.update(res, null, false, theRequestDetails);
} else { } else {
res.setId((String) null); res.setId((String) null);

View File

@ -1879,6 +1879,91 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
assertNull(nextEntry.getResource()); assertNull(nextEntry.getResource());
} }
@Test
public void testTransactionWithIfMatch() {
Patient p = new Patient();
p.setId("P1");
p.setActive(true);
myPatientDao.update(p);
p.setActive(false);
Bundle b = new Bundle();
b.setType(BundleType.TRANSACTION);
b.addEntry()
.setFullUrl("Patient/P1")
.setResource(p)
.getRequest()
.setMethod(HTTPVerb.PUT)
.setUrl("Patient/P1")
.setIfMatch("2");
try {
mySystemDao.transaction(mySrd, b);
} catch (ResourceVersionConflictException e) {
assertEquals("Trying to update Patient/P1/_history/2 but this is not the current version", e.getMessage());
}
b = new Bundle();
b.setType(BundleType.TRANSACTION);
b.addEntry()
.setFullUrl("Patient/P1")
.setResource(p)
.getRequest()
.setMethod(HTTPVerb.PUT)
.setUrl("Patient/P1")
.setIfMatch("1");
Bundle resp = mySystemDao.transaction(mySrd, b);
assertEquals("Patient/P1/_history/2", new IdType(resp.getEntry().get(0).getResponse().getLocation()).toUnqualified().getValue());
}
@Test
public void testTransactionWithIfNoneExist() {
Patient p = new Patient();
p.setId("P1");
p.setActive(true);
myPatientDao.update(p);
p = new Patient();
p.setActive(true);
p.addName().setFamily("AAA");
Bundle b = new Bundle();
b.setType(BundleType.TRANSACTION);
b.addEntry()
.setFullUrl("Patient")
.setResource(p)
.getRequest()
.setMethod(HTTPVerb.POST)
.setUrl("Patient/P1")
.setIfNoneExist("Patient?active=true");
Bundle resp = mySystemDao.transaction(mySrd, b);
assertEquals("Patient/P1/_history/1", new IdType(resp.getEntry().get(0).getResponse().getLocation()).toUnqualified().getValue());
p = new Patient();
p.setActive(true);
p.addName().setFamily("AAA");
b = new Bundle();
b.setType(BundleType.TRANSACTION);
b.addEntry()
.setFullUrl("Patient")
.setResource(p)
.getRequest()
.setMethod(HTTPVerb.POST)
.setUrl("Patient/P1")
.setIfNoneExist("Patient?active=false");
resp = mySystemDao.transaction(mySrd, b);
assertThat( new IdType(resp.getEntry().get(0).getResponse().getLocation()).toUnqualified().getValue(), matchesPattern("Patient/[0-9]+/_history/1"));
}
@Test @Test
public void testTransactionSearchWithCount() { public void testTransactionSearchWithCount() {
String methodName = "testTransactionSearchWithCount"; String methodName = "testTransactionSearchWithCount";

View File

@ -587,6 +587,90 @@ public class FhirSystemDaoR4Test extends BaseJpaR4SystemTest {
} }
@Test
public void testTransactionWithIfMatch() {
Patient p = new Patient();
p.setId("P1");
p.setActive(true);
myPatientDao.update(p);
p.setActive(false);
Bundle b = new Bundle();
b.setType(BundleType.TRANSACTION);
b.addEntry()
.setFullUrl("Patient/P1")
.setResource(p)
.getRequest()
.setMethod(HTTPVerb.PUT)
.setUrl("Patient/P1")
.setIfMatch("2");
try {
mySystemDao.transaction(mySrd, b);
} catch (ResourceVersionConflictException e) {
assertEquals("Trying to update Patient/P1/_history/2 but this is not the current version", e.getMessage());
}
b = new Bundle();
b.setType(BundleType.TRANSACTION);
b.addEntry()
.setFullUrl("Patient/P1")
.setResource(p)
.getRequest()
.setMethod(HTTPVerb.PUT)
.setUrl("Patient/P1")
.setIfMatch("1");
Bundle resp = mySystemDao.transaction(mySrd, b);
assertEquals("Patient/P1/_history/2", new IdType(resp.getEntry().get(0).getResponse().getLocation()).toUnqualified().getValue());
}
@Test
public void testTransactionWithIfNoneExist() {
Patient p = new Patient();
p.setId("P1");
p.setActive(true);
myPatientDao.update(p);
p = new Patient();
p.setActive(true);
p.addName().setFamily("AAA");
Bundle b = new Bundle();
b.setType(BundleType.TRANSACTION);
b.addEntry()
.setFullUrl("Patient")
.setResource(p)
.getRequest()
.setMethod(HTTPVerb.POST)
.setUrl("Patient/P1")
.setIfNoneExist("Patient?active=true");
Bundle resp = mySystemDao.transaction(mySrd, b);
assertEquals("Patient/P1/_history/1", new IdType(resp.getEntry().get(0).getResponse().getLocation()).toUnqualified().getValue());
p = new Patient();
p.setActive(true);
p.addName().setFamily("AAA");
b = new Bundle();
b.setType(BundleType.TRANSACTION);
b.addEntry()
.setFullUrl("Patient")
.setResource(p)
.getRequest()
.setMethod(HTTPVerb.POST)
.setUrl("Patient/P1")
.setIfNoneExist("Patient?active=false");
resp = mySystemDao.transaction(mySrd, b);
assertThat( new IdType(resp.getEntry().get(0).getResponse().getLocation()).toUnqualified().getValue(), matchesPattern("Patient/[0-9]+/_history/1"));
}
@Test @Test
public void testTransaction1() throws IOException { public void testTransaction1() throws IOException {
String inputBundleString = loadClasspath("/david-bundle-error.json"); String inputBundleString = loadClasspath("/david-bundle-error.json");

View File

@ -116,6 +116,20 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
return retVal; return retVal;
} }
@Test
public void testUpdateWrongResourceType() throws IOException {
String input = IOUtils.toString(getClass().getResourceAsStream("/dstu3-person.json"), StandardCharsets.UTF_8);
try {
MethodOutcome resp = ourClient.update().resource(input).withId("Patient/PERSON1").execute();
} catch (InvalidRequestException e) {
assertEquals("", e.getMessage());
}
MethodOutcome resp = ourClient.update().resource(input).withId("Person/PERSON1").execute();
assertEquals("Person/PERSON1/_history/1", resp.getId().toUnqualified().getValue());
}
/** /**
* See #484 * See #484
*/ */

View File

@ -0,0 +1,52 @@
{
"resourceType": "Person",
"id": "PERSON1",
"meta": {
"versionId": "1",
"lastUpdated": "2017-08-17T16:19:40.109+03:00"
},
"identifier": [
{
"value": "081181-9984"
}
],
"name": [
{
"text": "Anna Testi",
"family": "Testi",
"given": [
"Anna"
]
},
{
"family": "asdfas"
}
],
"telecom": [
{
"use": "home"
},
{
"system": "phone",
"value": "(044) 1234567",
"use": "work"
}
],
"gender": "female",
"birthDate": "1981-11-08",
"address": [
{
"line": [
"Osuuspankkitie 2"
],
"city": "Helsinki",
"postalCode": "00120",
"country": "Suomi"
},
{
"city": "Blo-49847020"
}
],
"active": true
}

View File

@ -59,6 +59,11 @@
Fix a NullPointerException when validating a Bundle (in DSTU3/R4) with no Fix a NullPointerException when validating a Bundle (in DSTU3/R4) with no
<![CDATA[<code>Bundle.type</code>]]> value <![CDATA[<code>Bundle.type</code>]]> value
</action> </action>
<action type="add">
The JPA server transaction operation (DSTU3/R4) did not correctly process the
If-Match header when passed in via
<![CDATA[<code>Bundle.entry.request.ifMatch</code>]]> value
</action>
</release> </release>
<release version="3.0.0" date="2017-09-27"> <release version="3.0.0" date="2017-09-27">
<action type="add"> <action type="add">