001/* 002 * #%L 003 * HAPI FHIR JAX-RS Server 004 * %% 005 * Copyright (C) 2014 - 2024 Smile CDR, Inc. 006 * %% 007 * Licensed under the Apache License, Version 2.0 (the "License"); 008 * you may not use this file except in compliance with the License. 009 * You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, software 014 * distributed under the License is distributed on an "AS IS" BASIS, 015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 * #L% 019 */ 020package ca.uhn.fhir.jaxrs.client; 021 022import ca.uhn.fhir.context.FhirContext; 023import ca.uhn.fhir.rest.api.Constants; 024import ca.uhn.fhir.rest.api.EncodingEnum; 025import ca.uhn.fhir.rest.api.RequestTypeEnum; 026import ca.uhn.fhir.rest.client.api.Header; 027import ca.uhn.fhir.rest.client.api.HttpClientUtil; 028import ca.uhn.fhir.rest.client.api.IHttpClient; 029import ca.uhn.fhir.rest.client.api.IHttpRequest; 030import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation; 031import ca.uhn.fhir.rest.client.method.MethodUtil; 032import jakarta.ws.rs.client.Client; 033import jakarta.ws.rs.client.Entity; 034import jakarta.ws.rs.client.Invocation.Builder; 035import jakarta.ws.rs.core.Form; 036import jakarta.ws.rs.core.MultivaluedHashMap; 037import jakarta.ws.rs.core.MultivaluedMap; 038import org.hl7.fhir.instance.model.api.IBaseBinary; 039 040import java.util.List; 041import java.util.Map; 042 043/** 044 * A Http Request based on JaxRs. This is an adapter around the class 045 * {@link jakarta.ws.rs.client.Client Client} 046 * 047 * @author Peter Van Houte | peter.vanhoute@agfa.com | Agfa Healthcare 048 */ 049public class JaxRsHttpClient implements IHttpClient { 050 051 private Client myClient; 052 private List<Header> myHeaders; 053 private StringBuilder myUrl; 054 private Map<String, List<String>> myIfNoneExistParams; 055 private String myIfNoneExistString; 056 private RequestTypeEnum myRequestType; 057 058 public JaxRsHttpClient( 059 Client theClient, 060 StringBuilder theUrl, 061 Map<String, List<String>> theIfNoneExistParams, 062 String theIfNoneExistString, 063 RequestTypeEnum theRequestType, 064 List<Header> theHeaders) { 065 this.myClient = theClient; 066 this.myUrl = theUrl; 067 this.myIfNoneExistParams = theIfNoneExistParams; 068 this.myIfNoneExistString = theIfNoneExistString; 069 this.myRequestType = theRequestType; 070 this.myHeaders = theHeaders; 071 } 072 073 @Override 074 public IHttpRequest createByteRequest( 075 FhirContext theContext, String theContents, String theContentType, EncodingEnum theEncoding) { 076 Entity<String> entity = Entity.entity(theContents, theContentType + Constants.HEADER_SUFFIX_CT_UTF_8); 077 JaxRsHttpRequest retVal = createHttpRequest(entity); 078 addHeadersToRequest(retVal, theEncoding, theContext); 079 retVal.addHeader(Constants.HEADER_CONTENT_TYPE, theContentType + Constants.HEADER_SUFFIX_CT_UTF_8); 080 return retVal; 081 } 082 083 @Override 084 public IHttpRequest createParamRequest( 085 FhirContext theContext, Map<String, List<String>> theParams, EncodingEnum theEncoding) { 086 MultivaluedMap<String, String> map = new MultivaluedHashMap<String, String>(); 087 for (Map.Entry<String, List<String>> nextParam : theParams.entrySet()) { 088 List<String> value = nextParam.getValue(); 089 for (String s : value) { 090 map.add(nextParam.getKey(), s); 091 } 092 } 093 Entity<Form> entity = Entity.form(map); 094 JaxRsHttpRequest retVal = createHttpRequest(entity); 095 addHeadersToRequest(retVal, theEncoding, theContext); 096 return retVal; 097 } 098 099 @Override 100 public IHttpRequest createBinaryRequest(FhirContext theContext, IBaseBinary theBinary) { 101 Entity<String> entity = Entity.entity(theBinary.getContentAsBase64(), theBinary.getContentType()); 102 JaxRsHttpRequest retVal = createHttpRequest(entity); 103 addHeadersToRequest(retVal, null, theContext); 104 return retVal; 105 } 106 107 @Override 108 public IHttpRequest createGetRequest(FhirContext theContext, EncodingEnum theEncoding) { 109 JaxRsHttpRequest result = createHttpRequest(null); 110 addHeadersToRequest(result, theEncoding, theContext); 111 return result; 112 } 113 114 public void addHeadersToRequest(JaxRsHttpRequest theHttpRequest, EncodingEnum theEncoding, FhirContext theContext) { 115 if (myHeaders != null) { 116 for (Header next : myHeaders) { 117 theHttpRequest.addHeader(next.getName(), next.getValue()); 118 } 119 } 120 121 theHttpRequest.addHeader("User-Agent", HttpClientUtil.createUserAgentString(theContext, "jax-rs")); 122 123 Builder request = theHttpRequest.getRequest(); 124 request.acceptEncoding("gzip"); 125 126 MethodUtil.addAcceptHeaderToRequest(theEncoding, theHttpRequest, theContext); 127 } 128 129 private JaxRsHttpRequest createHttpRequest(Entity<?> entity) { 130 Builder request = myClient.target(myUrl.toString()).request(); 131 JaxRsHttpRequest result = new JaxRsHttpRequest(request, myRequestType, entity); 132 addHeaderIfNoneExist(result); 133 return result; 134 } 135 136 private void addHeaderIfNoneExist(IHttpRequest result) { 137 if (myIfNoneExistParams != null) { 138 StringBuilder b = newHeaderBuilder(myUrl); 139 BaseHttpClientInvocation.appendExtraParamsWithQuestionMark(myIfNoneExistParams, b, b.indexOf("?") == -1); 140 result.addHeader(Constants.HEADER_IF_NONE_EXIST, b.toString()); 141 } 142 143 if (myIfNoneExistString != null) { 144 StringBuilder b = newHeaderBuilder(myUrl); 145 b.append(b.indexOf("?") == -1 ? '?' : '&'); 146 b.append(myIfNoneExistString.substring(myIfNoneExistString.indexOf('?') + 1)); 147 result.addHeader(Constants.HEADER_IF_NONE_EXIST, b.toString()); 148 } 149 } 150 151 private StringBuilder newHeaderBuilder(StringBuilder theUrlBase) { 152 StringBuilder b = new StringBuilder(); 153 b.append(theUrlBase); 154 if (theUrlBase.length() > 0 && theUrlBase.charAt(theUrlBase.length() - 1) == '/') { 155 b.deleteCharAt(b.length() - 1); 156 } 157 return b; 158 } 159}