From 9a72927dbc4acd4165669799dc722309156f534c Mon Sep 17 00:00:00 2001 From: James Agnew Date: Mon, 8 Jan 2018 14:07:01 -0500 Subject: [PATCH] Fix #808 - Use version from meta if not found in the resource ID --- ...hirResourceDaoR4UniqueSearchParamTest.java | 2 +- .../fhir/rest/server/RestfulServerUtils.java | 12 +- .../fhir/rest/server/ETagServerR4Test.java | 168 ++++++++++-------- src/changes/changes.xml | 5 + 4 files changed, 109 insertions(+), 78 deletions(-) rename hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/rest/server/ETagServerHl7OrgTest.java => hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/ETagServerR4Test.java (77%) diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4UniqueSearchParamTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4UniqueSearchParamTest.java index 5c40b0a460a..12f75f13436 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4UniqueSearchParamTest.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4UniqueSearchParamTest.java @@ -599,7 +599,7 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test { } }); - }er + } @Test public void testIndexFirstMatchOnly() { diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/RestfulServerUtils.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/RestfulServerUtils.java index cbe3dd0fa84..8758b3ff83e 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/RestfulServerUtils.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/RestfulServerUtils.java @@ -423,7 +423,7 @@ public class RestfulServerUtils { if (theResource instanceof IResource) { lastUpdated = ResourceMetadataKeyEnum.UPDATED.get((IResource) theResource); } else if (theResource instanceof IAnyResource) { - lastUpdated = new InstantDt(((IAnyResource) theResource).getMeta().getLastUpdated()); + lastUpdated = new InstantDt(theResource.getMeta().getLastUpdated()); } return lastUpdated; } @@ -561,11 +561,7 @@ public class RestfulServerUtils { String[] pretty = requestParams.get(Constants.PARAM_PRETTY); boolean prettyPrint; if (pretty != null && pretty.length > 0) { - if (Constants.PARAM_PRETTY_VALUE_TRUE.equals(pretty[0])) { - prettyPrint = true; - } else { - prettyPrint = false; - } + prettyPrint = Constants.PARAM_PRETTY_VALUE_TRUE.equals(pretty[0]); } else { prettyPrint = theServer.isDefaultPrettyPrint(); List acceptValues = theRequest.getHeaders(Constants.HEADER_ACCEPT); @@ -614,6 +610,8 @@ public class RestfulServerUtils { if (theServer.getETagSupport() == ETagSupportEnum.ENABLED) { if (fullId != null && fullId.hasVersionIdPart()) { response.addHeader(Constants.HEADER_ETAG, "W/\"" + fullId.getVersionIdPart() + '"'); + } else if (theResource != null && theResource.getMeta() != null && isNotBlank(theResource.getMeta().getVersionId())) { + response.addHeader(Constants.HEADER_ETAG, "W/\"" + theResource.getMeta().getVersionId() + '"'); } } @@ -730,7 +728,7 @@ public class RestfulServerUtils { } } - private static enum NarrativeModeEnum { + private enum NarrativeModeEnum { NORMAL, ONLY, SUPPRESS; public static NarrativeModeEnum valueOfCaseInsensitive(String theCode) { diff --git a/hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/rest/server/ETagServerHl7OrgTest.java b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/ETagServerR4Test.java similarity index 77% rename from hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/rest/server/ETagServerHl7OrgTest.java rename to hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/ETagServerR4Test.java index 73179813785..0fe52e59d86 100644 --- a/hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/rest/server/ETagServerHl7OrgTest.java +++ b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/ETagServerR4Test.java @@ -1,16 +1,22 @@ package ca.uhn.fhir.rest.server; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; - -import java.io.IOException; -import java.util.Date; -import java.util.concurrent.TimeUnit; - +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.primitive.InstantDt; +import ca.uhn.fhir.rest.annotation.IdParam; +import ca.uhn.fhir.rest.annotation.Read; +import ca.uhn.fhir.rest.annotation.ResourceParam; +import ca.uhn.fhir.rest.annotation.Update; +import ca.uhn.fhir.rest.api.Constants; +import ca.uhn.fhir.rest.api.MethodOutcome; +import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException; +import ca.uhn.fhir.util.PortUtil; +import com.google.common.base.Charsets; import org.apache.commons.io.IOUtils; import org.apache.http.Header; import org.apache.http.HttpResponse; -import org.apache.http.client.methods.*; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPut; import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; @@ -19,45 +25,33 @@ 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.instance.model.*; +import org.hl7.fhir.r4.model.IdType; +import org.hl7.fhir.r4.model.Identifier; +import org.hl7.fhir.r4.model.Patient; import org.junit.*; -import com.google.common.base.Charsets; +import java.util.Date; +import java.util.concurrent.TimeUnit; -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.model.primitive.InstantDt; -import ca.uhn.fhir.rest.annotation.*; -import ca.uhn.fhir.rest.api.Constants; -import ca.uhn.fhir.rest.api.MethodOutcome; -import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException; -import ca.uhn.fhir.util.PortUtil; +import static org.junit.Assert.*; -public class ETagServerHl7OrgTest { +public class ETagServerR4Test { private static CloseableHttpClient ourClient; - private static FhirContext ourCtx = FhirContext.forDstu2Hl7Org(); + private static FhirContext ourCtx = FhirContext.forR4(); private static Date ourLastModifiedDate; private static int ourPort; private static Server ourServer; private static PoolingHttpClientConnectionManager ourConnectionManager; + private static IdType ourLastId; + private static boolean ourPutVersionInPatientId; + private static boolean ourPutVersionInPatientMeta; - @Test - public void testETagHeader() throws Exception { - ourLastModifiedDate = new InstantDt("2012-11-25T02:34:45.2222Z").getValue(); - - HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/2/_history/3"); - HttpResponse status = ourClient.execute(httpGet); - String responseContent = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8); - IOUtils.closeQuietly(status.getEntity().getContent()); - - assertEquals(200, status.getStatusLine().getStatusCode()); - Identifier dt = ourCtx.newXmlParser().parseResource(Patient.class, responseContent).getIdentifier().get(0); - assertEquals("2", dt.getSystemElement().getValueAsString()); - assertEquals("3", dt.getValue()); - - Header cl = status.getFirstHeader(Constants.HEADER_ETAG_LC); - assertNotNull(cl); - assertEquals("W/\"222\"", cl.getValue()); + @Before + public void before() { + ourLastId = null; + ourPutVersionInPatientId = true; + ourPutVersionInPatientMeta = false; } @Test @@ -70,6 +64,42 @@ public class ETagServerHl7OrgTest { assertEquals(Constants.STATUS_HTTP_304_NOT_MODIFIED, status.getStatusLine().getStatusCode()); } + @Test + public void testETagHeader() throws Exception { + ourLastModifiedDate = new InstantDt("2012-11-25T02:34:45.2222Z").getValue(); + + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/2/_history/3"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + Identifier dt = ourCtx.newXmlParser().parseResource(Patient.class, responseContent).getIdentifier().get(0); + Assert.assertEquals("2", dt.getSystemElement().getValueAsString()); + Assert.assertEquals("3", dt.getValue()); + + Header cl = status.getFirstHeader(Constants.HEADER_ETAG_LC); + assertNotNull(cl); + assertEquals("W/\"222\"", cl.getValue()); + } + + @Test + public void testETagHeaderFromVersionInMeta() throws Exception { + ourPutVersionInPatientMeta = true; + ourPutVersionInPatientId = false; + ourLastModifiedDate = null; + + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/2/_history/3"); + HttpResponse status = ourClient.execute(httpGet); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + + Header cl = status.getFirstHeader(Constants.HEADER_ETAG_LC); + assertNotNull(cl); + assertEquals("W/\"333\"", cl.getValue()); + } + @Test public void testLastModifiedHeader() throws Exception { ourLastModifiedDate = new InstantDt("2012-11-25T02:34:45.2222Z").getValue(); @@ -81,35 +111,14 @@ public class ETagServerHl7OrgTest { assertEquals(200, status.getStatusLine().getStatusCode()); Identifier dt = ourCtx.newXmlParser().parseResource(Patient.class, responseContent).getIdentifier().get(0); - assertEquals("2", dt.getSystemElement().getValueAsString()); - assertEquals("3", dt.getValue()); + Assert.assertEquals("2", dt.getSystemElement().getValueAsString()); + Assert.assertEquals("3", dt.getValue()); Header cl = status.getFirstHeader(Constants.HEADER_LAST_MODIFIED_LOWERCASE); assertNotNull(cl); assertEquals("Sun, 25 Nov 2012 02:34:45 GMT", cl.getValue()); } - @Before - public void before() throws IOException { - ourLastId = null; - } - - @Test - public void testUpdateWithNoVersion() throws Exception { - Patient p = new Patient(); - p.setId("2"); - p.addIdentifier().setSystem("urn:system").setValue("001"); - String resBody = ourCtx.newXmlParser().encodeResourceToString(p); - - HttpPut http; - http = new HttpPut("http://localhost:" + ourPort + "/Patient/2"); - http.setEntity(new StringEntity(resBody, ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); - HttpResponse status = ourClient.execute(http); - IOUtils.closeQuietly(status.getEntity().getContent()); - assertEquals(200, status.getStatusLine().getStatusCode()); - - } - @Test public void testUpdateWithIfMatch() throws Exception { Patient p = new Patient(); @@ -124,7 +133,7 @@ public class ETagServerHl7OrgTest { CloseableHttpResponse status = ourClient.execute(http); IOUtils.closeQuietly(status.getEntity().getContent()); assertEquals(200, status.getStatusLine().getStatusCode()); - assertEquals("Patient/2/_history/221", ourLastId.toUnqualified().getValue()); + Assert.assertEquals("Patient/2/_history/221", ourLastId.toUnqualified().getValue()); } @@ -142,7 +151,23 @@ public class ETagServerHl7OrgTest { CloseableHttpResponse status = ourClient.execute(http); IOUtils.closeQuietly(status.getEntity().getContent()); assertEquals(Constants.STATUS_HTTP_412_PRECONDITION_FAILED, status.getStatusLine().getStatusCode()); - assertEquals("Patient/2/_history/222", ourLastId.toUnqualified().getValue()); + Assert.assertEquals("Patient/2/_history/222", ourLastId.toUnqualified().getValue()); + } + + @Test + public void testUpdateWithNoVersion() throws Exception { + Patient p = new Patient(); + p.setId("2"); + p.addIdentifier().setSystem("urn:system").setValue("001"); + String resBody = ourCtx.newXmlParser().encodeResourceToString(p); + + HttpPut http; + http = new HttpPut("http://localhost:" + ourPort + "/Patient/2"); + http.setEntity(new StringEntity(resBody, ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); + HttpResponse status = ourClient.execute(http); + IOUtils.closeQuietly(status.getEntity().getContent()); + assertEquals(200, status.getStatusLine().getStatusCode()); + } @AfterClass @@ -172,16 +197,24 @@ public class ETagServerHl7OrgTest { } - private static IdType ourLastId; - public static class PatientProvider implements IResourceProvider { + @Override + public Class getResourceType() { + return Patient.class; + } + @Read(version = true) - public Patient findPatient(@IdParam IdType theId) { + public Patient read(@IdParam IdType theId) { Patient patient = new Patient(); patient.getMeta().setLastUpdated(ourLastModifiedDate); patient.addIdentifier().setSystem(theId.getIdPart()).setValue(theId.getVersionIdPart()); - patient.setId(theId.withVersion("222")); + if (ourPutVersionInPatientId) { + patient.setId(theId.withVersion("222")); + } + if (ourPutVersionInPatientMeta) { + patient.getMeta().setVersionId("333"); + } return patient; } @@ -196,11 +229,6 @@ public class ETagServerHl7OrgTest { return new MethodOutcome(theId.withVersion(theId.getVersionIdPart() + "0")); } - @Override - public Class getResourceType() { - return Patient.class; - } - } } diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 883a4bf9917..e19a2589f5d 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -68,6 +68,11 @@ by interceptors to modify the request body before it is parsed by the server. + + Servers did not return an ETag if the version was provided on a + DSTU3/R4 structure in the getMeta() version field instead of in the + getIdElement() ID. Thanks to GitHub user @Chrisjobling for reporting! +