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