001package ca.uhn.hapi.converters.server; 002 003/*- 004 * #%L 005 * HAPI FHIR - Converter 006 * %% 007 * Copyright (C) 2014 - 2022 Smile CDR, Inc. 008 * %% 009 * Licensed under the Apache License, Version 2.0 (the "License"); 010 * you may not use this file except in compliance with the License. 011 * You may obtain a copy of the License at 012 * 013 * http://www.apache.org/licenses/LICENSE-2.0 014 * 015 * Unless required by applicable law or agreed to in writing, software 016 * distributed under the License is distributed on an "AS IS" BASIS, 017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 018 * See the License for the specific language governing permissions and 019 * limitations under the License. 020 * #L% 021 */ 022 023import ca.uhn.fhir.i18n.Msg; 024import ca.uhn.fhir.context.FhirContext; 025import ca.uhn.fhir.context.FhirVersionEnum; 026import ca.uhn.fhir.model.api.IResource; 027import ca.uhn.fhir.rest.api.Constants; 028import ca.uhn.fhir.rest.api.server.RequestDetails; 029import ca.uhn.fhir.rest.api.server.ResponseDetails; 030import ca.uhn.fhir.rest.server.exceptions.AuthenticationException; 031import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; 032import ca.uhn.fhir.rest.server.interceptor.InterceptorAdapter; 033import org.hl7.fhir.converter.NullVersionConverterAdvisor10_30; 034import org.hl7.fhir.converter.NullVersionConverterAdvisor10_40; 035import org.hl7.fhir.convertors.factory.VersionConvertorFactory_10_30; 036import org.hl7.fhir.convertors.factory.VersionConvertorFactory_10_40; 037import org.hl7.fhir.convertors.factory.VersionConvertorFactory_30_40; 038import org.hl7.fhir.dstu3.model.Resource; 039import org.hl7.fhir.exceptions.FHIRException; 040import org.hl7.fhir.instance.model.api.IBaseResource; 041 042import javax.servlet.http.HttpServletRequest; 043import javax.servlet.http.HttpServletResponse; 044import java.util.StringTokenizer; 045 046import static org.apache.commons.lang3.StringUtils.*; 047 048/** 049 * <b>This is an experimental interceptor! Use with caution as 050 * behaviour may change or be removed in a future version of 051 * FHIR.</b> 052 * <p> 053 * This interceptor partially implements the proposed 054 * Versioned API features. 055 * </p> 056 */ 057public class VersionedApiConverterInterceptor extends InterceptorAdapter { 058 private final FhirContext myCtxDstu2; 059 private final FhirContext myCtxDstu2Hl7Org; 060 private final NullVersionConverterAdvisor10_40 advisor40; 061 private final NullVersionConverterAdvisor10_30 advisor30; 062 063 public VersionedApiConverterInterceptor() { 064 advisor40 = new NullVersionConverterAdvisor10_40(); 065 advisor30 = new NullVersionConverterAdvisor10_30(); 066 067 myCtxDstu2 = FhirContext.forDstu2(); 068 myCtxDstu2Hl7Org = FhirContext.forDstu2Hl7Org(); 069 } 070 071 @Override 072 public boolean outgoingResponse(RequestDetails theRequestDetails, ResponseDetails theResponseDetails, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse) throws AuthenticationException { 073 IBaseResource responseResource = theResponseDetails.getResponseResource(); 074 if (responseResource == null) { 075 return true; 076 } 077 078 String[] formatParams = theRequestDetails.getParameters().get(Constants.PARAM_FORMAT); 079 String accept = null; 080 if (formatParams != null && formatParams.length > 0) { 081 accept = formatParams[0]; 082 } 083 if (isBlank(accept)) { 084 accept = defaultString(theServletRequest.getHeader(Constants.HEADER_ACCEPT)); 085 } 086 StringTokenizer tok = new StringTokenizer(accept, ";"); 087 String wantVersionString = null; 088 while (tok.hasMoreTokens()) { 089 String next = tok.nextToken().trim(); 090 if (next.startsWith("fhirVersion=")) { 091 wantVersionString = next.substring("fhirVersion=".length()).trim(); 092 break; 093 } 094 } 095 096 FhirVersionEnum wantVersion = null; 097 if (isNotBlank(wantVersionString)) { 098 wantVersion = FhirVersionEnum.forVersionString(wantVersionString); 099 } 100 101 FhirVersionEnum haveVersion = responseResource.getStructureFhirVersionEnum(); 102 103 IBaseResource converted = null; 104 try { 105 if (wantVersion == FhirVersionEnum.R4 && haveVersion == FhirVersionEnum.DSTU3) { 106 converted = VersionConvertorFactory_30_40.convertResource(toDstu3(responseResource)); 107 } else if (wantVersion == FhirVersionEnum.DSTU3 && haveVersion == FhirVersionEnum.R4) { 108 converted = VersionConvertorFactory_30_40.convertResource(toR4(responseResource)); 109 } else if (wantVersion == FhirVersionEnum.DSTU2 && haveVersion == FhirVersionEnum.R4) { 110 converted = VersionConvertorFactory_10_40.convertResource(toR4(responseResource), advisor40); 111 } else if (wantVersion == FhirVersionEnum.R4 && haveVersion == FhirVersionEnum.DSTU2) { 112 converted = VersionConvertorFactory_10_40.convertResource(toDstu2(responseResource), advisor40); 113 } else if (wantVersion == FhirVersionEnum.DSTU2 && haveVersion == FhirVersionEnum.DSTU3) { 114 converted = VersionConvertorFactory_10_30.convertResource(toDstu3(responseResource), advisor30); 115 } else if (wantVersion == FhirVersionEnum.DSTU3 && haveVersion == FhirVersionEnum.DSTU2) { 116 converted = VersionConvertorFactory_10_30.convertResource(toDstu2(responseResource), advisor30); 117 } 118 } catch (FHIRException e) { 119 throw new InternalErrorException(Msg.code(73) + e); 120 } 121 122 if (converted != null) { 123 theResponseDetails.setResponseResource(converted); 124 } 125 126 return true; 127 } 128 129 private org.hl7.fhir.dstu2.model.Resource toDstu2(IBaseResource theResponseResource) { 130 if (theResponseResource instanceof IResource) { 131 return (org.hl7.fhir.dstu2.model.Resource) myCtxDstu2Hl7Org.newJsonParser().parseResource(myCtxDstu2.newJsonParser().encodeResourceToString(theResponseResource)); 132 } 133 return (org.hl7.fhir.dstu2.model.Resource) theResponseResource; 134 } 135 136 private Resource toDstu3(IBaseResource theResponseResource) { 137 return (Resource) theResponseResource; 138 } 139 140 private org.hl7.fhir.r4.model.Resource toR4(IBaseResource theResponseResource) { 141 return (org.hl7.fhir.r4.model.Resource) theResponseResource; 142 } 143}