001package ca.uhn.fhir.rest.client.apache;
002
003/*
004 * #%L
005 * HAPI FHIR - Client Framework
006 * %%
007 * Copyright (C) 2014 - 2023 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 java.io.UnsupportedEncodingException;
025import java.util.*;
026import java.util.Map.Entry;
027
028import org.apache.http.HttpEntity;
029import org.apache.http.NameValuePair;
030import org.apache.http.client.HttpClient;
031import org.apache.http.client.entity.UrlEncodedFormEntity;
032import org.apache.http.client.methods.*;
033import org.apache.http.entity.ByteArrayEntity;
034import org.apache.http.message.BasicNameValuePair;
035
036import ca.uhn.fhir.rest.api.Constants;
037import ca.uhn.fhir.rest.api.RequestTypeEnum;
038import ca.uhn.fhir.rest.client.api.*;
039import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
040
041/**
042 * A Http Client based on Apache. This is an adapter around the class
043 * {@link org.apache.http.client.HttpClient HttpClient}
044 * 
045 * @author Peter Van Houte | peter.vanhoute@agfa.com | Agfa Healthcare
046 */
047public class ApacheHttpClient extends BaseHttpClient implements IHttpClient {
048
049        private final HttpClient myClient;
050
051        public ApacheHttpClient(HttpClient theClient, StringBuilder theUrl, Map<String, List<String>> theIfNoneExistParams, String theIfNoneExistString, RequestTypeEnum theRequestType, List<Header> theHeaders) {
052                super(theUrl, theIfNoneExistParams, theIfNoneExistString, theRequestType, theHeaders);
053                this.myClient = theClient;
054        }
055
056        private HttpRequestBase constructRequestBase(HttpEntity theEntity) {
057                String url = myUrl.toString();
058                switch (myRequestType) {
059                case DELETE:
060                        return new HttpDelete(url);
061                case PATCH:
062                        HttpPatch httpPatch = new HttpPatch(url);
063                        httpPatch.setEntity(theEntity);
064                        return httpPatch;
065                case OPTIONS:
066                        return new HttpOptions(url);
067                case POST:
068                        HttpPost httpPost = new HttpPost(url);
069                        httpPost.setEntity(theEntity);
070                        return httpPost;
071                case PUT:
072                        HttpPut httpPut = new HttpPut(url);
073                        httpPut.setEntity(theEntity);
074                        return httpPut;
075                case GET:
076                default:
077                        return new HttpGet(url);
078                }
079        }
080
081
082        private UrlEncodedFormEntity createFormEntity(List<NameValuePair> parameters) {
083                try {
084                        return new UrlEncodedFormEntity(parameters, "UTF-8");
085                } catch (UnsupportedEncodingException e) {
086                        throw new InternalErrorException(Msg.code(1479) + "Server does not support UTF-8 (should not happen)", e);
087                }
088        }
089
090
091        @Override
092        protected IHttpRequest createHttpRequest() {
093                return createHttpRequest((HttpEntity)null);
094        }
095
096        @Override
097        protected IHttpRequest createHttpRequest(byte[] content) {
098                /*
099                 * Note: Be careful about changing which constructor we use for
100                 * ByteArrayEntity, as Android's version of HTTPClient doesn't support
101                 * the newer ones for whatever reason.
102                 */
103                ByteArrayEntity entity = new ByteArrayEntity(content);
104                return createHttpRequest(entity);
105        }
106
107        private ApacheHttpRequest createHttpRequest(HttpEntity theEntity) {
108                HttpRequestBase request = constructRequestBase(theEntity);
109                return new ApacheHttpRequest(myClient, request);
110        }
111
112        @Override
113        protected IHttpRequest createHttpRequest(Map<String, List<String>> theParams) {
114                List<NameValuePair> parameters = new ArrayList<>();
115                for (Entry<String, List<String>> nextParam : theParams.entrySet()) {
116                        List<String> value = nextParam.getValue();
117                        for (String s : value) {
118                                parameters.add(new BasicNameValuePair(nextParam.getKey(), s));
119                        }
120                }
121
122                UrlEncodedFormEntity entity = createFormEntity(parameters);
123                return createHttpRequest(entity);
124        }
125
126
127        @Override
128        protected IHttpRequest createHttpRequest(String theContents) {
129                /*
130                 * We aren't using a StringEntity here because the constructors
131                 * supported by Android aren't available in non-Android, and vice versa.
132                 * Since we add the content type header manually, it makes no difference
133                 * which one we use anyhow.
134                 */
135                ByteArrayEntity entity = new ByteArrayEntity(theContents.getBytes(Constants.CHARSET_UTF8));
136                return createHttpRequest(entity);
137        }
138}