An experimental interceptor called VersionedApiConverterInterceptor has been added, which automaticaly converts response payloads to a client-specified version according to transforms built into FHIR.
This commit is contained in:
parent
a89c8d50c5
commit
e52f582769
|
@ -9,9 +9,9 @@ package ca.uhn.fhir.context;
|
|||
* 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.
|
||||
|
@ -40,16 +40,14 @@ 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()),
|
||||
|
||||
R4("org.hl7.fhir.r4.hapi.ctx.FhirR4", null, true, new R4Version()),
|
||||
|
||||
;
|
||||
DSTU3("org.hl7.fhir.dstu3.hapi.ctx.FhirDstu3", null, true, new Dstu3Version()),
|
||||
|
||||
R4("org.hl7.fhir.r4.hapi.ctx.FhirR4", null, true, new R4Version()),;
|
||||
|
||||
private final FhirVersionEnum myEquivalent;
|
||||
private final boolean myIsRi;
|
||||
private volatile Boolean myPresentOnClasspath;
|
||||
private final String myVersionClass;
|
||||
private volatile Boolean myPresentOnClasspath;
|
||||
private volatile IFhirVersion myVersionImplementation;
|
||||
private String myFhirVersionString;
|
||||
|
||||
|
@ -82,21 +80,6 @@ public enum FhirVersionEnum {
|
|||
return ordinal() >= theVersion.ordinal();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link FhirVersionEnum} which corresponds to a specific version of
|
||||
* FHIR. Partial version strings (e.g. "3.0") are acceptable.
|
||||
*
|
||||
* @return Returns null if no version exists matching the given string
|
||||
*/
|
||||
public static FhirVersionEnum forVersionString(String theVersionString) {
|
||||
for (FhirVersionEnum next : values()) {
|
||||
if (next.getFhirVersionString().startsWith(theVersionString)) {
|
||||
return next;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isEquivalentTo(FhirVersionEnum theVersion) {
|
||||
if (this.equals(theVersion)) {
|
||||
return true;
|
||||
|
@ -139,15 +122,50 @@ public enum FhirVersionEnum {
|
|||
return myIsRi;
|
||||
}
|
||||
|
||||
public FhirContext newContext() {
|
||||
switch (this) {
|
||||
case DSTU2:
|
||||
return FhirContext.forDstu2();
|
||||
case DSTU2_HL7ORG:
|
||||
return FhirContext.forDstu2Hl7Org();
|
||||
case DSTU2_1:
|
||||
return FhirContext.forDstu2_1();
|
||||
case DSTU3:
|
||||
return FhirContext.forDstu3();
|
||||
case R4:
|
||||
return FhirContext.forR4();
|
||||
}
|
||||
throw new IllegalStateException("Unknown version: " + this); // should not happen
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link FhirVersionEnum} which corresponds to a specific version of
|
||||
* FHIR. Partial version strings (e.g. "3.0") are acceptable.
|
||||
*
|
||||
* @return Returns null if no version exists matching the given string
|
||||
*/
|
||||
public static FhirVersionEnum forVersionString(String theVersionString) {
|
||||
for (FhirVersionEnum next : values()) {
|
||||
if (next.getFhirVersionString().startsWith(theVersionString)) {
|
||||
return next;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private interface IVersionProvider {
|
||||
String provideVersion();
|
||||
}
|
||||
|
||||
private static class Version implements IVersionProvider {
|
||||
|
||||
private String myVersion;
|
||||
|
||||
public Version(String theVersion) {
|
||||
super();
|
||||
myVersion = theVersion;
|
||||
}
|
||||
|
||||
private String myVersion;
|
||||
|
||||
@Override
|
||||
public String provideVersion() {
|
||||
return myVersion;
|
||||
|
@ -155,17 +173,14 @@ public enum FhirVersionEnum {
|
|||
|
||||
}
|
||||
|
||||
private interface IVersionProvider {
|
||||
String provideVersion();
|
||||
}
|
||||
|
||||
/**
|
||||
* This class attempts to read the FHIR version from the actual model
|
||||
* classes in order to supply an accurate version string even over time
|
||||
*
|
||||
*/
|
||||
private static class Dstu3Version implements IVersionProvider {
|
||||
|
||||
private String myVersion;
|
||||
|
||||
public Dstu3Version() {
|
||||
try {
|
||||
Class<?> c = Class.forName("org.hl7.fhir.dstu3.model.Constants");
|
||||
|
@ -175,8 +190,6 @@ public enum FhirVersionEnum {
|
|||
}
|
||||
}
|
||||
|
||||
private String myVersion;
|
||||
|
||||
@Override
|
||||
public String provideVersion() {
|
||||
return myVersion;
|
||||
|
@ -186,6 +199,8 @@ public enum FhirVersionEnum {
|
|||
|
||||
private static class R4Version implements IVersionProvider {
|
||||
|
||||
private String myVersion;
|
||||
|
||||
public R4Version() {
|
||||
try {
|
||||
Class<?> c = Class.forName("org.hl7.fhir.r4.model.Constants");
|
||||
|
@ -195,8 +210,6 @@ public enum FhirVersionEnum {
|
|||
}
|
||||
}
|
||||
|
||||
private String myVersion;
|
||||
|
||||
@Override
|
||||
public String provideVersion() {
|
||||
return myVersion;
|
||||
|
|
|
@ -32,6 +32,12 @@
|
|||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-structures-dstu2</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-structures-hl7org-dstu2</artifactId>
|
||||
|
@ -70,6 +76,11 @@
|
|||
</dependency>
|
||||
|
||||
<!-- Testing -->
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-client</artifactId>
|
||||
|
|
|
@ -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.*;
|
||||
|
||||
/**
|
||||
* <b>This is an experimental interceptor! Use with caution as
|
||||
* behaviour may change or be removed in a future version of
|
||||
* FHIR.</b>
|
||||
* <p>
|
||||
* This interceptor partially implements the proposed
|
||||
* Versioned API features.
|
||||
* </p>
|
||||
*/
|
||||
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<SummaryEnum> 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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<Patient> retVal = new ArrayList<Patient>();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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<Patient> retVal = new ArrayList<>();
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.getIdElement().setValue("Patient/A");
|
||||
patient.addName(new HumanName().setFamily("FAMILY"));
|
||||
retVal.add(patient);
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
<configuration>
|
||||
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
||||
<level>INFO</level>
|
||||
</filter>
|
||||
<encoder>
|
||||
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} [%file:%line] %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<logger name="org.springframework.web.socket.handler.ExceptionWebSocketHandlerDecorator" additivity="false" level="info">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</logger>
|
||||
|
||||
<logger name="ca.uhn.fhir.jpa.dao.FhirResourceDaoSubscriptionDstu2" additivity="false" level="info">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</logger>
|
||||
|
||||
<logger name="org.eclipse.jetty.websocket" additivity="false" level="info">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</logger>
|
||||
|
||||
<logger name="org.eclipse" additivity="false" level="error">
|
||||
</logger>
|
||||
|
||||
<logger name="ca.uhn.fhir.rest.client" additivity="false" level="info">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</logger>
|
||||
|
||||
<logger name="ca.uhn.fhir.jpa.dao" additivity="false" level="info">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</logger>
|
||||
|
||||
<!-- Set to 'trace' to enable SQL logging -->
|
||||
<logger name="org.hibernate.SQL" additivity="false" level="info">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</logger>
|
||||
<!-- Set to 'trace' to enable SQL Value logging -->
|
||||
<logger name="org.hibernate.type" additivity="false" level="info">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</logger>
|
||||
|
||||
<root level="info">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
|
||||
</configuration>
|
|
@ -91,7 +91,7 @@ public class JaxRsResponse extends RestfulResponse<JaxRsRequest> {
|
|||
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);
|
||||
|
|
|
@ -155,6 +155,11 @@
|
|||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-dbcp2</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-converter</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ import ca.uhn.fhir.rest.server.interceptor.CorsInterceptor;
|
|||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||
import ca.uhn.fhir.rest.server.interceptor.ResponseHighlighterInterceptor;
|
||||
import ca.uhn.fhirtest.config.*;
|
||||
import ca.uhn.hapi.converters.server.VersionedApiConverterInterceptor;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.web.context.ContextLoaderListener;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
@ -176,6 +177,11 @@ public class TestRestfulServer extends RestfulServer {
|
|||
CorsInterceptor corsInterceptor = new CorsInterceptor();
|
||||
registerInterceptor(corsInterceptor);
|
||||
|
||||
/*
|
||||
* Enable version conversion
|
||||
*/
|
||||
registerInterceptor(new VersionedApiConverterInterceptor());
|
||||
|
||||
/*
|
||||
* We want to format the response using nice HTML if it's a browser, since this
|
||||
* makes things a little easier for testers.
|
||||
|
|
|
@ -9,9 +9,9 @@ package ca.uhn.fhir.rest.server;
|
|||
* 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.
|
||||
|
@ -58,6 +58,7 @@ public class RestfulServerUtils {
|
|||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RestfulServerUtils.class);
|
||||
|
||||
private static final HashSet<String> TEXT_ENCODE_ELEMENTS = new HashSet<String>(Arrays.asList("Bundle", "*.text", "*.(mandatory)"));
|
||||
private static Map<FhirVersionEnum, FhirContext> myFhirContextMap = Collections.synchronizedMap(new HashMap<FhirVersionEnum, FhirContext>());
|
||||
|
||||
public static void configureResponseParser(RequestDetails theRequestDetails, IParser parser) {
|
||||
// Pretty print
|
||||
|
@ -266,7 +267,7 @@ public class RestfulServerUtils {
|
|||
* Some browsers (e.g. FF) request "application/xml" in their Accept header,
|
||||
* and we generally want to treat this as a preference for FHIR XML even if
|
||||
* it's not the FHIR version of the CT, which should be "application/xml+fhir".
|
||||
*
|
||||
*
|
||||
* When we're serving up Binary resources though, we are a bit more strict,
|
||||
* since Binary is supposed to use native content types unless the client has
|
||||
* explicitly requested FHIR.
|
||||
|
@ -433,7 +434,9 @@ public class RestfulServerUtils {
|
|||
if (theResourceId.hasIdPart() && isNotBlank(theServerBase)) {
|
||||
String resName = theResourceId.getResourceType();
|
||||
if (theResource != null && isBlank(resName)) {
|
||||
resName = theServer.getFhirContext().getResourceDefinition(theResource).getName();
|
||||
FhirContext context = theServer.getFhirContext();
|
||||
context = getContextForVersion(context, theResource.getStructureFhirVersionEnum());
|
||||
resName = context.getResourceDefinition(theResource).getName();
|
||||
}
|
||||
if (isNotBlank(resName)) {
|
||||
retVal = theResourceId.withServerBase(theServerBase, resName);
|
||||
|
@ -455,18 +458,19 @@ public class RestfulServerUtils {
|
|||
return new ResponseEncoding(theFhirContext, encoding, theContentType);
|
||||
}
|
||||
|
||||
public static IParser getNewParser(FhirContext theContext, RequestDetails theRequestDetails) {
|
||||
public static IParser getNewParser(FhirContext theContext, FhirVersionEnum theForVersion, RequestDetails theRequestDetails) {
|
||||
FhirContext context = getContextForVersion(theContext, theForVersion);
|
||||
|
||||
// Determine response encoding
|
||||
EncodingEnum responseEncoding = RestfulServerUtils.determineResponseEncodingWithDefault(theRequestDetails).getEncoding();
|
||||
IParser parser;
|
||||
switch (responseEncoding) {
|
||||
case JSON:
|
||||
parser = theContext.newJsonParser();
|
||||
parser = context.newJsonParser();
|
||||
break;
|
||||
case XML:
|
||||
default:
|
||||
parser = theContext.newXmlParser();
|
||||
parser = context.newXmlParser();
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -475,6 +479,18 @@ public class RestfulServerUtils {
|
|||
return parser;
|
||||
}
|
||||
|
||||
private static FhirContext getContextForVersion(FhirContext theContext, FhirVersionEnum theForVersion) {
|
||||
FhirContext context = theContext;
|
||||
if (context.getVersion().getVersion() != theForVersion) {
|
||||
context = myFhirContextMap.get(theForVersion);
|
||||
if (context == null) {
|
||||
context = theForVersion.newContext();
|
||||
myFhirContextMap.put(theForVersion, context);
|
||||
}
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
public static Set<String> parseAcceptHeaderAndReturnHighestRankedOptions(HttpServletRequest theRequest) {
|
||||
Set<String> retVal = new HashSet<String>();
|
||||
|
||||
|
@ -689,7 +705,8 @@ public class RestfulServerUtils {
|
|||
} else if (encodingDomainResourceAsText && theResource instanceof IResource) {
|
||||
writer.append(((IResource) theResource).getText().getDiv().getValueAsString());
|
||||
} else {
|
||||
IParser parser = getNewParser(theServer.getFhirContext(), theRequestDetails);
|
||||
FhirVersionEnum forVersion = theResource.getStructureFhirVersionEnum();
|
||||
IParser parser = getNewParser(theServer.getFhirContext(), forVersion, theRequestDetails);
|
||||
parser.encodeResourceToWriter(theResource, writer);
|
||||
}
|
||||
//FIXME resource leak
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package ca.uhn.fhir.rest.server.interceptor;
|
||||
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.parser.IParser;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
|
@ -392,7 +393,7 @@ public class ResponseHighlighterInterceptor extends InterceptorAdapter {
|
|||
}
|
||||
}
|
||||
|
||||
private void streamResponse(RequestDetails theRequestDetails, HttpServletResponse theServletResponse, IBaseResource resource, ServletRequest theServletRequest, int theStatusCode) {
|
||||
private void streamResponse(RequestDetails theRequestDetails, HttpServletResponse theServletResponse, IBaseResource theResource, ServletRequest theServletRequest, int theStatusCode) {
|
||||
|
||||
if (theRequestDetails.getServer() instanceof RestfulServer) {
|
||||
RestfulServer rs = (RestfulServer) theRequestDetails.getServer();
|
||||
|
@ -402,7 +403,8 @@ public class ResponseHighlighterInterceptor extends InterceptorAdapter {
|
|||
IParser p;
|
||||
Map<String, String[]> parameters = theRequestDetails.getParameters();
|
||||
if (parameters.containsKey(Constants.PARAM_FORMAT)) {
|
||||
p = RestfulServerUtils.getNewParser(theRequestDetails.getServer().getFhirContext(), theRequestDetails);
|
||||
FhirVersionEnum forVersion = theResource.getStructureFhirVersionEnum();
|
||||
p = RestfulServerUtils.getNewParser(theRequestDetails.getServer().getFhirContext(), forVersion, theRequestDetails);
|
||||
} else {
|
||||
EncodingEnum defaultResponseEncoding = theRequestDetails.getServer().getDefaultResponseEncoding();
|
||||
p = defaultResponseEncoding.newParser(theRequestDetails.getServer().getFhirContext());
|
||||
|
@ -423,7 +425,7 @@ public class ResponseHighlighterInterceptor extends InterceptorAdapter {
|
|||
}
|
||||
|
||||
EncodingEnum encoding = p.getEncoding();
|
||||
String encoded = p.encodeResourceToString(resource);
|
||||
String encoded = p.encodeResourceToString(theResource);
|
||||
|
||||
try {
|
||||
|
||||
|
@ -615,7 +617,7 @@ public class ResponseHighlighterInterceptor extends InterceptorAdapter {
|
|||
b.append("\n");
|
||||
|
||||
InputStream jsStream = ResponseHighlighterInterceptor.class.getResourceAsStream("ResponseHighlighter.js");
|
||||
String jsStr = jsStream != null ? IOUtils.toString(jsStream, "UTF-8") : "console.log('ResponseHighlighterInterceptor: javascript resource not found')";
|
||||
String jsStr = jsStream != null ? IOUtils.toString(jsStream, "UTF-8") : "console.log('ResponseHighlighterInterceptor: javascript theResource not found')";
|
||||
jsStr = jsStr.replace("FHIR_BASE", theRequestDetails.getServerBaseForRequest());
|
||||
b.append("<script type=\"text/javascript\">");
|
||||
b.append(jsStr);
|
||||
|
|
|
@ -74,6 +74,11 @@
|
|||
it is possible to perform Schematron validation on Java 9. Thanks to
|
||||
Mark Grimes for reporting and suggesting a fix!
|
||||
</action>
|
||||
<action type="add">
|
||||
An experimental interceptor called VersionedApiConverterInterceptor has been added,
|
||||
which automaticaly converts response payloads to a client-specified version
|
||||
according to transforms built into FHIR.
|
||||
</action>
|
||||
</release>
|
||||
<release version="3.2.0" date="2018-01-13">
|
||||
<action type="add">
|
||||
|
|
Loading…
Reference in New Issue