From 1743d108b68fdf1b97c2e7966be06e3970d59e52 Mon Sep 17 00:00:00 2001 From: Clayton Bodendein Date: Sun, 6 Aug 2017 14:03:15 -0500 Subject: [PATCH 1/2] Fixed #705 by making RestfulClientFactory check for the correct FHIR version strings when the client code tries to validate the server's conformance statement. Also fixed the corresponding unit tests. --- .../ca/uhn/fhir/context/FhirVersionEnum.java | 22 +------- .../rest/client/RestfulClientFactory.java | 9 ++-- .../provider/ServerConformanceProvider.java | 3 +- .../ClientServerValidationDstu1Test.java | 6 +-- .../dstu2/ServerConformanceProvider.java | 3 +- .../ClientServerValidationDstu2Test.java | 50 +++---------------- .../conf/ServerConformanceProvider.java | 3 +- ...ClientServerValidationTestHl7OrgDstu2.java | 45 ++--------------- 8 files changed, 24 insertions(+), 117 deletions(-) diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/FhirVersionEnum.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/FhirVersionEnum.java index 7400211ba0f..8a001a68ae6 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/FhirVersionEnum.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/FhirVersionEnum.java @@ -42,7 +42,7 @@ public enum FhirVersionEnum { DSTU2_1("org.hl7.fhir.dstu2016may.hapi.ctx.FhirDstu2_1", null, true, new Version("1.4.0")), - DSTU3("org.hl7.fhir.dstu3.hapi.ctx.FhirDstu3", null, true, new Dstu3Version()); + DSTU3("org.hl7.fhir.dstu3.hapi.ctx.FhirDstu3", null, true, new Version("3.0.1")); private final FhirVersionEnum myEquivalent; private final boolean myIsRi; @@ -138,24 +138,4 @@ public enum FhirVersionEnum { String provideVersion(); } - private static class Dstu3Version implements IVersionProvider { - - public Dstu3Version() { - try { - Class c = Class.forName("org.hl7.fhir.dstu3.model.Constants"); - myVersion = (String) c.getDeclaredField("VERSION").get(null); - } catch (Exception e) { - myVersion = "UNKNOWN"; - } - } - - private String myVersion; - - @Override - public String provideVersion() { - return myVersion; - } - - } - } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/RestfulClientFactory.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/RestfulClientFactory.java index a1c787e47cb..dd7b1f1b642 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/RestfulClientFactory.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/RestfulClientFactory.java @@ -325,13 +325,12 @@ public abstract class RestfulClientFactory implements IRestfulClientFactory { if (StringUtils.isBlank(serverFhirVersionString)) { // we'll be lenient and accept this } else { - //FIXME null access on serverFhirVersionString - if (serverFhirVersionString.startsWith("0.80") || serverFhirVersionString.startsWith("0.0.8")) { + if (serverFhirVersionString.equals(FhirVersionEnum.DSTU1.getFhirVersionString())) { serverFhirVersionEnum = FhirVersionEnum.DSTU1; - } else if (serverFhirVersionString.startsWith("0.4")) { - serverFhirVersionEnum = FhirVersionEnum.DSTU2; - } else if (serverFhirVersionString.startsWith("0.5")) { + } else if (serverFhirVersionString.equals(FhirVersionEnum.DSTU2.getFhirVersionString())) { serverFhirVersionEnum = FhirVersionEnum.DSTU2; + } else if (serverFhirVersionString.equals(FhirVersionEnum.DSTU3.getFhirVersionString())) { + serverFhirVersionEnum = FhirVersionEnum.DSTU3; } else { // we'll be lenient and accept this ourLog.debug("Server conformance statement indicates unknown FHIR version: {}", serverFhirVersionString); diff --git a/hapi-fhir-structures-dstu/src/main/java/ca/uhn/fhir/rest/server/provider/ServerConformanceProvider.java b/hapi-fhir-structures-dstu/src/main/java/ca/uhn/fhir/rest/server/provider/ServerConformanceProvider.java index 01c8bcfca32..83c83e6f412 100644 --- a/hapi-fhir-structures-dstu/src/main/java/ca/uhn/fhir/rest/server/provider/ServerConformanceProvider.java +++ b/hapi-fhir-structures-dstu/src/main/java/ca/uhn/fhir/rest/server/provider/ServerConformanceProvider.java @@ -31,6 +31,7 @@ import java.util.TreeSet; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; +import ca.uhn.fhir.context.FhirVersionEnum; import org.apache.commons.lang3.StringUtils; import org.hl7.fhir.instance.model.api.IBaseResource; @@ -125,7 +126,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider capt = ArgumentCaptor.forClass(HttpUriRequest.class); @@ -89,7 +89,7 @@ public class ClientServerValidationDstu1Test { @Test public void testServerReturnsWrongVersionDstu() throws Exception { Conformance conf = new Conformance(); - conf.setFhirVersion("0.4.0"); + conf.setFhirVersion("1.0.2"); String msg = myCtx.newXmlParser().encodeResourceToString(conf); ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); @@ -105,7 +105,7 @@ public class ClientServerValidationDstu1Test { myCtx.newRestfulGenericClient("http://foo").read(new UriDt("http://foo/Patient/1")); fail(); } catch (FhirClientInappropriateForServerException e) { - assertThat(e.toString(), containsString("The server at base URL \"http://foo/metadata\" returned a conformance statement indicating that it supports FHIR version \"0.4.0\" which corresponds to DSTU2, but this client is configured to use DSTU1 (via the FhirContext)")); + assertThat(e.toString(), containsString("The server at base URL \"http://foo/metadata\" returned a conformance statement indicating that it supports FHIR version \"1.0.2\" which corresponds to DSTU2, but this client is configured to use DSTU1 (via the FhirContext)")); } } diff --git a/hapi-fhir-structures-dstu2/src/main/java/ca/uhn/fhir/rest/server/provider/dstu2/ServerConformanceProvider.java b/hapi-fhir-structures-dstu2/src/main/java/ca/uhn/fhir/rest/server/provider/dstu2/ServerConformanceProvider.java index b61ba3b5762..1fb37fffd5e 100644 --- a/hapi-fhir-structures-dstu2/src/main/java/ca/uhn/fhir/rest/server/provider/dstu2/ServerConformanceProvider.java +++ b/hapi-fhir-structures-dstu2/src/main/java/ca/uhn/fhir/rest/server/provider/dstu2/ServerConformanceProvider.java @@ -38,6 +38,7 @@ import java.util.TreeSet; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; +import ca.uhn.fhir.context.FhirVersionEnum; import org.apache.commons.lang3.StringUtils; import org.hl7.fhir.instance.model.api.IBaseResource; @@ -196,7 +197,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider capt = ArgumentCaptor.forClass(HttpUriRequest.class); @@ -112,7 +112,7 @@ public class ClientServerValidationDstu2Test { @Test public void testForceConformanceCheck() throws Exception { Conformance conf = new Conformance(); - conf.setFhirVersion("0.5.0"); + conf.setFhirVersion("1.0.2"); final String confResource = myCtx.newXmlParser().encodeResourceToString(conf); ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); @@ -181,47 +181,9 @@ public class ClientServerValidationDstu2Test { } @Test - public void testServerReturnsAppropriateVersionForDstu2_040() throws Exception { + public void testServerReturnsAppropriateVersionForDstu2() throws Exception { Conformance conf = new Conformance(); - conf.setFhirVersion("0.5.0"); - final String confResource = myCtx.newXmlParser().encodeResourceToString(conf); - - ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); - - when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); - when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); - when(myHttpResponse.getEntity().getContent()).thenAnswer(new Answer() { - @Override - public InputStream answer(InvocationOnMock theInvocation) throws Throwable { - if (myFirstResponse) { - myFirstResponse = false; - return new ReaderInputStream(new StringReader(confResource), Charset.forName("UTF-8")); - } else { - return new ReaderInputStream(new StringReader(myCtx.newXmlParser().encodeResourceToString(new Patient())), Charset.forName("UTF-8")); - } - } - }); - - when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); - - myCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.ONCE); - IGenericClient client = myCtx.newRestfulGenericClient("http://foo"); - - // don't load the conformance until the first time the client is actually used - assertTrue(myFirstResponse); - client.read(new UriDt("http://foo/Patient/123")); - assertFalse(myFirstResponse); - myCtx.newRestfulGenericClient("http://foo").read(new UriDt("http://foo/Patient/123")); - myCtx.newRestfulGenericClient("http://foo").read(new UriDt("http://foo/Patient/123")); - - // Conformance only loaded once, then 3 reads - verify(myHttpClient, times(4)).execute(Matchers.any(HttpUriRequest.class)); - } - - @Test - public void testServerReturnsAppropriateVersionForDstu2_050() throws Exception { - Conformance conf = new Conformance(); - conf.setFhirVersion("0.5.0"); + conf.setFhirVersion("1.0.2"); final String confResource = myCtx.newXmlParser().encodeResourceToString(conf); ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); @@ -259,7 +221,7 @@ public class ClientServerValidationDstu2Test { @Test public void testServerReturnsWrongVersionForDstu2() throws Exception { Conformance conf = new Conformance(); - conf.setFhirVersion("0.80"); + conf.setFhirVersion("0.0.82"); String msg = myCtx.newXmlParser().encodeResourceToString(conf); ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); @@ -276,7 +238,7 @@ public class ClientServerValidationDstu2Test { fail(); } catch (FhirClientInappropriateForServerException e) { String out = e.toString(); - String want = "The server at base URL \"http://foo/metadata\" returned a conformance statement indicating that it supports FHIR version \"0.80\" which corresponds to DSTU1, but this client is configured to use DSTU2 (via the FhirContext)"; + String want = "The server at base URL \"http://foo/metadata\" returned a conformance statement indicating that it supports FHIR version \"0.0.82\" which corresponds to DSTU1, but this client is configured to use DSTU2 (via the FhirContext)"; ourLog.info(out); ourLog.info(want); assertThat(out, containsString(want)); diff --git a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/conf/ServerConformanceProvider.java b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/conf/ServerConformanceProvider.java index 4eeb7533235..c04e93d5300 100644 --- a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/conf/ServerConformanceProvider.java +++ b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/conf/ServerConformanceProvider.java @@ -43,6 +43,7 @@ import java.util.jar.Manifest; import javax.servlet.http.HttpServletRequest; +import ca.uhn.fhir.context.FhirVersionEnum; import org.apache.commons.lang3.StringUtils; import org.hl7.fhir.instance.model.Conformance; import org.hl7.fhir.instance.model.Conformance.ConditionalDeleteStatus; @@ -192,7 +193,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider capt = ArgumentCaptor.forClass(HttpUriRequest.class); - - when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); - when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); - when(myHttpResponse.getEntity().getContent()).thenAnswer(new Answer() { - @Override - public InputStream answer(InvocationOnMock theInvocation) throws Throwable { - if (myFirstResponse) { - myFirstResponse=false; - return new ReaderInputStream(new StringReader(confResource), Charset.forName("UTF-8")); - } else { - return new ReaderInputStream(new StringReader(myCtx.newXmlParser().encodeResourceToString(new Patient())), Charset.forName("UTF-8")); - } - }}); - - when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); - - myCtx.getRestfulClientFactory().setServerValidationModeEnum(ServerValidationModeEnum.ONCE); - IGenericClient client = myCtx.newRestfulGenericClient("http://foo"); - - // don't load the conformance until the first time the client is actually used - assertTrue(myFirstResponse); - client.read(new UriDt("http://foo/Patient/123")); - assertFalse(myFirstResponse); - myCtx.newRestfulGenericClient("http://foo").read(new UriDt("http://foo/Patient/123")); - myCtx.newRestfulGenericClient("http://foo").read(new UriDt("http://foo/Patient/123")); - - // Conformance only loaded once, then 3 reads - verify(myHttpClient, times(4)).execute(Matchers.any(HttpUriRequest.class)); - } - - @Test - public void testServerReturnsAppropriateVersionForDstu2_050() throws Exception { - Conformance conf = new Conformance(); - conf.setFhirVersion("0.5.0"); + conf.setFhirVersion("1.0.2"); final String confResource = myCtx.newXmlParser().encodeResourceToString(conf); ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); @@ -132,7 +95,7 @@ public class ClientServerValidationTestHl7OrgDstu2 { @Test public void testServerReturnsWrongVersionForDstu2() throws Exception { Conformance conf = new Conformance(); - conf.setFhirVersion("0.80"); + conf.setFhirVersion("0.0.82"); String msg = myCtx.newXmlParser().encodeResourceToString(conf); ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); @@ -149,7 +112,7 @@ public class ClientServerValidationTestHl7OrgDstu2 { fail(); } catch (FhirClientInappropriateForServerException e) { String out = e.toString(); - String want = "The server at base URL \"http://foo/metadata\" returned a conformance statement indicating that it supports FHIR version \"0.80\" which corresponds to DSTU1, but this client is configured to use DSTU2_HL7ORG (via the FhirContext)"; + String want = "The server at base URL \"http://foo/metadata\" returned a conformance statement indicating that it supports FHIR version \"0.0.82\" which corresponds to DSTU1, but this client is configured to use DSTU2_HL7ORG (via the FhirContext)"; ourLog.info(out); ourLog.info(want); assertThat(out, containsString(want)); From 9a32202d0386ded3e5ee77191f3703ed4466df1b Mon Sep 17 00:00:00 2001 From: Clayton Bodendein Date: Sun, 6 Aug 2017 21:27:05 -0500 Subject: [PATCH 2/2] Also related to issue #705, added an explicit check for DSTU2.1 as well when the client checks the server's conformance statement FHIR version --- .../main/java/ca/uhn/fhir/rest/client/RestfulClientFactory.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/RestfulClientFactory.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/RestfulClientFactory.java index dd7b1f1b642..0d06f7dbad4 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/RestfulClientFactory.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/RestfulClientFactory.java @@ -329,6 +329,8 @@ public abstract class RestfulClientFactory implements IRestfulClientFactory { serverFhirVersionEnum = FhirVersionEnum.DSTU1; } else if (serverFhirVersionString.equals(FhirVersionEnum.DSTU2.getFhirVersionString())) { serverFhirVersionEnum = FhirVersionEnum.DSTU2; + } else if (serverFhirVersionString.equals(FhirVersionEnum.DSTU2_1.getFhirVersionString())) { + serverFhirVersionEnum = FhirVersionEnum.DSTU2_1; } else if (serverFhirVersionString.equals(FhirVersionEnum.DSTU3.getFhirVersionString())) { serverFhirVersionEnum = FhirVersionEnum.DSTU3; } else {