ca.uhn.hapi.fhir
hapi-fhir-client
diff --git a/hapi-fhir-converter/src/main/java/ca/uhn/hapi/converters/server/VersionedApiConverterInterceptor.java b/hapi-fhir-converter/src/main/java/ca/uhn/hapi/converters/server/VersionedApiConverterInterceptor.java
index 04a4cd432e5..bdebfb7db7e 100644
--- a/hapi-fhir-converter/src/main/java/ca/uhn/hapi/converters/server/VersionedApiConverterInterceptor.java
+++ b/hapi-fhir-converter/src/main/java/ca/uhn/hapi/converters/server/VersionedApiConverterInterceptor.java
@@ -1,39 +1,68 @@
package ca.uhn.hapi.converters.server;
+import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum;
+import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.rest.api.Constants;
-import ca.uhn.fhir.rest.api.SummaryEnum;
import ca.uhn.fhir.rest.api.server.RequestDetails;
-import ca.uhn.fhir.rest.server.RestfulServerUtils;
+import ca.uhn.fhir.rest.api.server.ResponseDetails;
import ca.uhn.fhir.rest.server.exceptions.AuthenticationException;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.interceptor.InterceptorAdapter;
-import org.hl7.fhir.convertors.VersionConvertor_30_40;
+import org.hl7.fhir.convertors.*;
+import org.hl7.fhir.dstu3.model.Resource;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.instance.model.api.IBaseResource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-import java.util.Collections;
-import java.util.Set;
import java.util.StringTokenizer;
-import static org.apache.commons.lang3.StringUtils.defaultString;
-import static org.apache.commons.lang3.StringUtils.isNotBlank;
+import static org.apache.commons.lang3.StringUtils.*;
+/**
+ * This is an experimental interceptor! Use with caution as
+ * behaviour may change or be removed in a future version of
+ * FHIR.
+ *
+ * This interceptor partially implements the proposed
+ * Versioned API features.
+ *
+ */
public class VersionedApiConverterInterceptor extends InterceptorAdapter {
- private VersionConvertor_30_40 myVersionConvertor_30_40 = new VersionConvertor_30_40();
+ private final FhirContext myCtxDstu2;
+ private final FhirContext myCtxDstu2Hl7Org;
+ private VersionConvertor_30_40 myVersionConvertor_30_40;
+ private VersionConvertor_10_40 myVersionConvertor_10_40;
+ private VersionConvertor_10_30 myVersionConvertor_10_30;
+
+ public VersionedApiConverterInterceptor() {
+ myVersionConvertor_30_40 = new VersionConvertor_30_40();
+ VersionConvertorAdvisor40 advisor40 = new NullVersionConverterAdvisor40();
+ myVersionConvertor_10_40 = new VersionConvertor_10_40(advisor40);
+ VersionConvertorAdvisor30 advisor30 = new NullVersionConverterAdvisor30();
+ myVersionConvertor_10_30 = new VersionConvertor_10_30(advisor30);
+
+ myCtxDstu2 = FhirContext.forDstu2();
+ myCtxDstu2Hl7Org = FhirContext.forDstu2Hl7Org();
+ }
@Override
- public boolean outgoingResponse(RequestDetails theRequestDetails, IBaseResource theResponseObject, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse) throws AuthenticationException {
- String accept = defaultString(theServletRequest.getHeader(Constants.HEADER_ACCEPT));
+ public boolean outgoingResponse(RequestDetails theRequestDetails, ResponseDetails theResponseDetails, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse) throws AuthenticationException {
+ String[] formatParams = theRequestDetails.getParameters().get(Constants.PARAM_FORMAT);
+ String accept = null;
+ if (formatParams != null && formatParams.length > 0) {
+ accept = formatParams[0];
+ }
+ if (isBlank(accept)) {
+ accept = defaultString(theServletRequest.getHeader(Constants.HEADER_ACCEPT));
+ }
StringTokenizer tok = new StringTokenizer(accept, ";");
String wantVersionString = null;
while (tok.hasMoreTokens()) {
String next = tok.nextToken().trim();
- if (next.startsWith("fhir-version=")) {
- wantVersionString = next.substring("fhir-version=".length()).trim();
+ if (next.startsWith("fhirVersion=")) {
+ wantVersionString = next.substring("fhirVersion=".length()).trim();
break;
}
}
@@ -42,31 +71,48 @@ public class VersionedApiConverterInterceptor extends InterceptorAdapter {
if (isNotBlank(wantVersionString)) {
wantVersion = FhirVersionEnum.forVersionString(wantVersionString);
}
- FhirVersionEnum haveVersion = theResponseObject.getStructureFhirVersionEnum();
+
+ IBaseResource responseResource = theResponseDetails.getResponseResource();
+ FhirVersionEnum haveVersion = responseResource.getStructureFhirVersionEnum();
IBaseResource converted = null;
try {
if (wantVersion == FhirVersionEnum.R4 && haveVersion == FhirVersionEnum.DSTU3) {
- converted = myVersionConvertor_30_40.convertResource((org.hl7.fhir.dstu3.model.Resource) theResponseObject);
+ converted = myVersionConvertor_30_40.convertResource(toDstu3(responseResource));
} else if (wantVersion == FhirVersionEnum.DSTU3 && haveVersion == FhirVersionEnum.R4) {
- converted = myVersionConvertor_30_40.convertResource((org.hl7.fhir.r4.model.Resource) theResponseObject);
- } else if (wantVersion == FhirVersionEnum.DSTU3 && haveVersion == FhirVersionEnum.R4) {
- converted = myVersionConvertor_30_40.convertResource((org.hl7.fhir.r4.model.Resource) theResponseObject);
+ converted = myVersionConvertor_30_40.convertResource(toR4(responseResource));
+ } else if (wantVersion == FhirVersionEnum.DSTU2 && haveVersion == FhirVersionEnum.R4) {
+ converted = myVersionConvertor_10_40.convertResource(toR4(responseResource));
+ } else if (wantVersion == FhirVersionEnum.R4 && haveVersion == FhirVersionEnum.DSTU2) {
+ converted = myVersionConvertor_10_40.convertResource(toDstu2(responseResource));
+ } else if (wantVersion == FhirVersionEnum.DSTU2 && haveVersion == FhirVersionEnum.DSTU3) {
+ converted = myVersionConvertor_10_30.convertResource(toDstu3(responseResource));
+ } else if (wantVersion == FhirVersionEnum.DSTU3 && haveVersion == FhirVersionEnum.DSTU2) {
+ converted = myVersionConvertor_10_30.convertResource(toDstu2(responseResource));
}
} catch (FHIRException e) {
throw new InternalErrorException(e);
}
if (converted != null) {
- Set objects = Collections.emptySet();
- try {
- RestfulServerUtils.streamResponseAsResource(theRequestDetails.getServer(), converted, objects, 200, "OK", false, false, theRequestDetails, null, null);
- return false;
- } catch (IOException e) {
- throw new InternalErrorException(e);
- }
+ theResponseDetails.setResponseResource(converted);
}
return true;
}
+
+ private org.hl7.fhir.instance.model.Resource toDstu2(IBaseResource theResponseResource) {
+ if (theResponseResource instanceof IResource) {
+ return (org.hl7.fhir.instance.model.Resource) myCtxDstu2Hl7Org.newJsonParser().parseResource(myCtxDstu2.newJsonParser().encodeResourceToString(theResponseResource));
+ }
+ return (org.hl7.fhir.instance.model.Resource) theResponseResource;
+ }
+
+ private Resource toDstu3(IBaseResource theResponseResource) {
+ return (Resource) theResponseResource;
+ }
+
+ private org.hl7.fhir.r4.model.Resource toR4(IBaseResource theResponseResource) {
+ return (org.hl7.fhir.r4.model.Resource) theResponseResource;
+ }
}
diff --git a/hapi-fhir-converter/src/main/java/org/hl7/fhir/convertors/NullVersionConverterAdvisor40.java b/hapi-fhir-converter/src/main/java/org/hl7/fhir/convertors/NullVersionConverterAdvisor40.java
new file mode 100644
index 00000000000..22219b57aae
--- /dev/null
+++ b/hapi-fhir-converter/src/main/java/org/hl7/fhir/convertors/NullVersionConverterAdvisor40.java
@@ -0,0 +1,56 @@
+package org.hl7.fhir.convertors;
+
+/*
+ * #%L
+ * HAPI FHIR - Converter
+ * %%
+ * Copyright (C) 2014 - 2018 University Health Network
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * #L%
+ */
+
+import org.hl7.fhir.exceptions.FHIRException;
+import org.hl7.fhir.instance.model.Resource;
+import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent;
+import org.hl7.fhir.r4.model.CodeSystem;
+import org.hl7.fhir.r4.model.ValueSet;
+
+public class NullVersionConverterAdvisor40 implements VersionConvertorAdvisor40 {
+
+ @Override
+ public Resource convertR2(org.hl7.fhir.r4.model.Resource resource) throws FHIRException {
+ return null;
+ }
+
+ @Override
+ public org.hl7.fhir.dstu3.model.Resource convertR3(org.hl7.fhir.r4.model.Resource resource) throws FHIRException {
+ return null;
+ }
+
+ @Override
+ public CodeSystem getCodeSystem(ValueSet theSrc) {
+ return null;
+ }
+
+ @Override
+ public void handleCodeSystem(CodeSystem theTgtcs, ValueSet theSource) {
+ //nothing
+ }
+
+ @Override
+ public boolean ignoreEntry(BundleEntryComponent theSrc) {
+ return false;
+ }
+
+}
diff --git a/hapi-fhir-converter/src/test/java/ca/uhn/hapi/converters/server/SearchDstu3Test.java b/hapi-fhir-converter/src/test/java/ca/uhn/hapi/converters/server/SearchDstu3Test.java
deleted file mode 100644
index ed659016d8a..00000000000
--- a/hapi-fhir-converter/src/test/java/ca/uhn/hapi/converters/server/SearchDstu3Test.java
+++ /dev/null
@@ -1,276 +0,0 @@
-package ca.uhn.hapi.converters.server;
-
-import ca.uhn.fhir.context.FhirContext;
-import ca.uhn.fhir.rest.annotation.RequiredParam;
-import ca.uhn.fhir.rest.annotation.Search;
-import ca.uhn.fhir.rest.api.Constants;
-import ca.uhn.fhir.rest.api.EncodingEnum;
-import ca.uhn.fhir.rest.api.SearchStyleEnum;
-import ca.uhn.fhir.rest.client.api.IGenericClient;
-import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
-import ca.uhn.fhir.rest.gclient.StringClientParam;
-import ca.uhn.fhir.rest.param.TokenAndListParam;
-import ca.uhn.fhir.rest.server.FifoMemoryPagingProvider;
-import ca.uhn.fhir.rest.server.IResourceProvider;
-import ca.uhn.fhir.rest.server.RestfulServer;
-import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
-import ca.uhn.fhir.util.PortUtil;
-import ca.uhn.fhir.util.TestUtil;
-import ca.uhn.fhir.util.UrlUtil;
-import org.apache.commons.io.IOUtils;
-import org.apache.http.client.ClientProtocolException;
-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.Bundle;
-import org.hl7.fhir.dstu3.model.HumanName;
-import org.hl7.fhir.dstu3.model.OperationOutcome;
-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 java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-import static org.hamcrest.Matchers.containsString;
-import static org.hamcrest.Matchers.not;
-import static org.junit.Assert.*;
-
-public class SearchDstu3Test {
-
- private static CloseableHttpClient ourClient;
- private static FhirContext ourCtx = FhirContext.forDstu3();
- private static TokenAndListParam ourIdentifiers;
- private static String ourLastMethod;
- private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchDstu3Test.class);
- private static int ourPort;
-
- private static Server ourServer;
-
- @Before
- public void before() {
- ourLastMethod = null;
- ourIdentifiers = null;
- }
-
- @Test
- public void testSearchNormal() throws Exception {
- HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo%7Cbar");
- CloseableHttpResponse status = ourClient.execute(httpGet);
- try {
- String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
- ourLog.info(responseContent);
- assertEquals(200, status.getStatusLine().getStatusCode());
-
- assertEquals("search", ourLastMethod);
-
- assertEquals("foo", ourIdentifiers.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens().get(0).getSystem());
- assertEquals("bar", ourIdentifiers.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens().get(0).getValue());
- } finally {
- IOUtils.closeQuietly(status.getEntity().getContent());
- }
-
- }
-
- @Test
- public void testSearchWithInvalidChain() throws Exception {
- HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier.chain=foo%7Cbar");
- CloseableHttpResponse status = ourClient.execute(httpGet);
- try {
- String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
- ourLog.info(responseContent);
- assertEquals(400, status.getStatusLine().getStatusCode());
-
- OperationOutcome oo = (OperationOutcome) ourCtx.newJsonParser().parseResource(responseContent);
- assertEquals(
- "Invalid search parameter \"identifier.chain\". Parameter contains a chain (.chain) and chains are not supported for this parameter (chaining is only allowed on reference parameters)",
- oo.getIssueFirstRep().getDiagnostics());
- } finally {
- IOUtils.closeQuietly(status.getEntity().getContent());
- }
-
- }
-
-
- @Test
- public void testPagingPreservesEncodingJson() throws Exception {
- HttpGet httpGet;
- String linkNext;
- Bundle bundle;
-
- // Initial search
- httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo%7Cbar&_format=json");
- bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
- linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
- assertThat(linkNext, containsString("_format=json"));
-
- // Fetch the next page
- httpGet = new HttpGet(linkNext);
- bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
- linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
- assertThat(linkNext, containsString("_format=json"));
-
- // Fetch the next page
- httpGet = new HttpGet(linkNext);
- bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
- linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
- assertThat(linkNext, containsString("_format=json"));
-
- // Fetch the next page
- httpGet = new HttpGet(linkNext);
- bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
- linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
- assertThat(linkNext, containsString("_format=json"));
-
- }
-
- @Test
- public void testPagingPreservesEncodingApplicationJsonFhir() throws Exception {
- HttpGet httpGet;
- String linkNext;
- Bundle bundle;
-
- // Initial search
- httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo%7Cbar&_format=" + Constants.CT_FHIR_JSON_NEW);
- bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
- linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
- assertThat(linkNext, containsString("_format=" + UrlUtil.escapeUrlParam(Constants.CT_FHIR_JSON_NEW)));
-
- // Fetch the next page
- httpGet = new HttpGet(linkNext);
- bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
- linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
- assertThat(linkNext, containsString("_format=" + UrlUtil.escapeUrlParam(Constants.CT_FHIR_JSON_NEW)));
-
- // Fetch the next page
- httpGet = new HttpGet(linkNext);
- bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
- linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
- assertThat(linkNext, containsString("_format=" + UrlUtil.escapeUrlParam(Constants.CT_FHIR_JSON_NEW)));
-
- // Fetch the next page
- httpGet = new HttpGet(linkNext);
- bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
- linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
- assertThat(linkNext, containsString("_format=" + UrlUtil.escapeUrlParam(Constants.CT_FHIR_JSON_NEW)));
-
- }
-
-
- private Bundle executeAndReturnLinkNext(HttpGet httpGet, EncodingEnum theExpectEncoding) throws IOException {
- CloseableHttpResponse status = ourClient.execute(httpGet);
- Bundle bundle;
- try {
- String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
- ourLog.info(responseContent);
- assertEquals(200, status.getStatusLine().getStatusCode());
- EncodingEnum ct = EncodingEnum.forContentType(status.getEntity().getContentType().getValue().replaceAll(";.*", "").trim());
- assertEquals(theExpectEncoding, ct);
- bundle = ct.newParser(ourCtx).parseResource(Bundle.class, responseContent);
- assertEquals(10, bundle.getEntry().size());
- String linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
- assertNotNull(linkNext);
- } finally {
- IOUtils.closeQuietly(status.getEntity().getContent());
- }
- return bundle;
- }
-
-
- @Test
- public void testSearchWithPostAndInvalidParameters() {
- IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort);
- LoggingInterceptor interceptor = new LoggingInterceptor();
- interceptor.setLogRequestSummary(true);
- interceptor.setLogRequestBody(true);
- interceptor.setLogRequestHeaders(false);
- interceptor.setLogResponseBody(false);
- interceptor.setLogResponseHeaders(false);
- interceptor.setLogResponseSummary(false);
- client.registerInterceptor(interceptor);
- try {
- client
- .search()
- .forResource(Patient.class)
- .where(new StringClientParam("foo").matches().value("bar"))
- .prettyPrint()
- .usingStyle(SearchStyleEnum.POST)
- .returnBundle(Bundle.class)
- .encodedJson()
- .execute();
- fail();
- } catch (InvalidRequestException e) {
- assertThat(e.getMessage(), containsString("Invalid request: The FHIR endpoint on this server does not know how to handle POST operation[Patient/_search] with parameters [[_pretty, foo]]"));
- }
-
- }
-
- @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.setDefaultResponseEncoding(EncodingEnum.JSON);
- 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;
- }
-
- @SuppressWarnings("rawtypes")
- @Search()
- public List search(
- @RequiredParam(name = Patient.SP_IDENTIFIER) TokenAndListParam theIdentifiers) {
- ourLastMethod = "search";
- ourIdentifiers = theIdentifiers;
- ArrayList retVal = new ArrayList();
-
- for (int i = 0; i < 200; i++) {
- Patient patient = new Patient();
- patient.addName(new HumanName().setFamily("FAMILY"));
- patient.getIdElement().setValue("Patient/" + i);
- retVal.add(patient);
- }
- return retVal;
- }
-
- }
-
-}
diff --git a/hapi-fhir-converter/src/test/java/ca/uhn/hapi/converters/server/VersionedApiConverterInterceptorR4Test.java b/hapi-fhir-converter/src/test/java/ca/uhn/hapi/converters/server/VersionedApiConverterInterceptorR4Test.java
new file mode 100644
index 00000000000..c6c357b2bad
--- /dev/null
+++ b/hapi-fhir-converter/src/test/java/ca/uhn/hapi/converters/server/VersionedApiConverterInterceptorR4Test.java
@@ -0,0 +1,131 @@
+package ca.uhn.hapi.converters.server;
+
+import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.rest.annotation.Search;
+import ca.uhn.fhir.rest.api.EncodingEnum;
+import ca.uhn.fhir.rest.server.FifoMemoryPagingProvider;
+import ca.uhn.fhir.rest.server.IResourceProvider;
+import ca.uhn.fhir.rest.server.RestfulServer;
+import ca.uhn.fhir.util.PortUtil;
+import ca.uhn.fhir.util.TestUtil;
+import ca.uhn.fhir.util.UrlUtil;
+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.BeforeClass;
+import org.junit.Test;
+
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+public class VersionedApiConverterInterceptorR4Test {
+
+ private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(VersionedApiConverterInterceptorR4Test.class);
+ private static CloseableHttpClient ourClient;
+ private static FhirContext ourCtx = FhirContext.forDstu3();
+ private static int ourPort;
+
+ private static Server ourServer;
+
+
+ @Test
+ public void testSearchNormal() throws Exception {
+ HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient");
+ try (CloseableHttpResponse status = ourClient.execute(httpGet)) {
+ String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
+ ourLog.info(responseContent);
+ assertThat(responseContent, containsString("\"family\": \"FAMILY\""));
+ }
+ }
+
+ @Test
+ public void testSearchConvertToR2() throws Exception {
+ HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient");
+ httpGet.addHeader("Accept", "application/fhir+json; fhirVersion=1.0");
+ try (CloseableHttpResponse status = ourClient.execute(httpGet)) {
+ String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
+ ourLog.info(responseContent);
+ assertThat(responseContent, containsString("\"family\": ["));
+ }
+ }
+
+ @Test
+ public void testSearchConvertToR2ByFormatParam() throws Exception {
+ HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_format=" + UrlUtil.escapeUrlParam("application/fhir+json; fhirVersion=1.0"));
+ try (CloseableHttpResponse status = ourClient.execute(httpGet)) {
+ String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
+ ourLog.info(responseContent);
+ assertThat(responseContent, containsString("\"family\": ["));
+ }
+ }
+
+ @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.setDefaultResponseEncoding(EncodingEnum.JSON);
+ servlet.setDefaultPrettyPrint(true);
+ servlet.registerInterceptor(new VersionedApiConverterInterceptor());
+
+ 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;
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Search()
+ public List search() {
+ ArrayList retVal = new ArrayList<>();
+
+ Patient patient = new Patient();
+ patient.getIdElement().setValue("Patient/A");
+ patient.addName(new HumanName().setFamily("FAMILY"));
+ retVal.add(patient);
+
+ return retVal;
+ }
+
+ }
+
+}
diff --git a/hapi-fhir-converter/src/test/resources/logback-test.xml b/hapi-fhir-converter/src/test/resources/logback-test.xml
new file mode 100644
index 00000000000..91f8a74d3e2
--- /dev/null
+++ b/hapi-fhir-converter/src/test/resources/logback-test.xml
@@ -0,0 +1,48 @@
+
+
+
+
+ INFO
+
+
+ %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} [%file:%line] %msg%n
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/util/JaxRsResponse.java b/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/util/JaxRsResponse.java
index 9071b801603..182421e83c0 100644
--- a/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/util/JaxRsResponse.java
+++ b/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/util/JaxRsResponse.java
@@ -91,7 +91,7 @@ public class JaxRsResponse extends RestfulResponse {
StringWriter writer = new StringWriter();
if (outcome != null) {
FhirContext fhirContext = getRequestDetails().getServer().getFhirContext();
- IParser parser = RestfulServerUtils.getNewParser(fhirContext, getRequestDetails());
+ IParser parser = RestfulServerUtils.getNewParser(fhirContext, fhirContext.getVersion().getVersion(), getRequestDetails());
outcome.execute(parser, writer);
}
return sendWriterResponse(operationStatus, getParserType(), null, writer);
diff --git a/hapi-fhir-jpaserver-uhnfhirtest/pom.xml b/hapi-fhir-jpaserver-uhnfhirtest/pom.xml
index 025558219df..2dfc1ec5008 100644
--- a/hapi-fhir-jpaserver-uhnfhirtest/pom.xml
+++ b/hapi-fhir-jpaserver-uhnfhirtest/pom.xml
@@ -155,6 +155,11 @@
org.apache.commons
commons-dbcp2
+