001package ca.uhn.fhir.rest.client.apache;
002
003/*
004 * #%L
005 * HAPI FHIR - Client Framework
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.context.FhirContext;
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.impl.RestfulClientFactory;
028import org.apache.http.HttpHost;
029import org.apache.http.auth.AuthScope;
030import org.apache.http.auth.UsernamePasswordCredentials;
031import org.apache.http.client.CredentialsProvider;
032import org.apache.http.client.HttpClient;
033import org.apache.http.client.config.RequestConfig;
034import org.apache.http.impl.client.BasicCredentialsProvider;
035import org.apache.http.impl.client.HttpClientBuilder;
036import org.apache.http.impl.client.HttpClients;
037import org.apache.http.impl.client.ProxyAuthenticationStrategy;
038import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
039
040import java.util.List;
041import java.util.Map;
042import java.util.concurrent.TimeUnit;
043
044import static org.apache.commons.lang3.StringUtils.isNotBlank;
045
046/**
047 * A Restful Factory to create clients, requests and responses based on the Apache httpclient library.
048 * 
049 * @author Peter Van Houte | peter.vanhoute@agfa.com | Agfa Healthcare
050 */
051public class ApacheRestfulClientFactory extends RestfulClientFactory {
052
053        private HttpClient myHttpClient;
054        private HttpHost myProxy;
055
056        /**
057         * Constructor
058         */
059        public ApacheRestfulClientFactory() {
060                super();
061        }
062
063        /**
064         * Constructor
065         * 
066         * @param theContext
067         *            The context
068         */
069        public ApacheRestfulClientFactory(FhirContext theContext) {
070                super(theContext);
071        }
072
073        @Override
074        protected synchronized IHttpClient getHttpClient(String theServerBase) {
075                return getHttpClient(new StringBuilder(theServerBase), null, null, null, null);
076        }
077
078        @Override
079        public synchronized IHttpClient getHttpClient(StringBuilder theUrl, Map<String, List<String>> theIfNoneExistParams,
080                                                                                                                                 String theIfNoneExistString, RequestTypeEnum theRequestType, List<Header> theHeaders) {
081                return new ApacheHttpClient(getNativeHttpClient(), theUrl, theIfNoneExistParams, theIfNoneExistString, theRequestType, theHeaders);
082        }
083
084        public HttpClient getNativeHttpClient() {
085                if (myHttpClient == null) {
086
087                        //TODO: Use of a deprecated method should be resolved.
088                        RequestConfig defaultRequestConfig =
089                                RequestConfig.custom()
090                                        .setSocketTimeout(getSocketTimeout())
091                                        .setConnectTimeout(getConnectTimeout())
092                                        .setConnectionRequestTimeout(getConnectionRequestTimeout())
093                                        .setStaleConnectionCheckEnabled(true)
094                                        .setProxy(myProxy)
095                                        .build();
096
097                        HttpClientBuilder builder = getHttpClientBuilder()
098                                .useSystemProperties()
099                                .setDefaultRequestConfig(defaultRequestConfig)
100                                .disableCookieManagement();
101
102                        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
103                        connectionManager.setMaxTotal(getPoolMaxTotal());
104                        connectionManager.setDefaultMaxPerRoute(getPoolMaxPerRoute());
105                        builder.setConnectionManager(connectionManager);
106
107                        if (myProxy != null && isNotBlank(getProxyUsername()) && isNotBlank(getProxyPassword())) {
108                                CredentialsProvider credsProvider = new BasicCredentialsProvider();
109                                credsProvider.setCredentials(new AuthScope(myProxy.getHostName(), myProxy.getPort()),
110                                                new UsernamePasswordCredentials(getProxyUsername(), getProxyPassword()));
111                                builder.setProxyAuthenticationStrategy(new ProxyAuthenticationStrategy());
112                                builder.setDefaultCredentialsProvider(credsProvider);
113                        }
114
115                        myHttpClient = builder.build();
116
117                }
118
119                return myHttpClient;
120        }
121
122        protected HttpClientBuilder getHttpClientBuilder() {
123                return HttpClients.custom();
124        }
125
126        @Override
127        protected void resetHttpClient() {
128                this.myHttpClient = null;
129        }
130
131        /**
132         * Only allows to set an instance of type org.apache.http.client.HttpClient
133         * @see ca.uhn.fhir.rest.client.api.IRestfulClientFactory#setHttpClient(Object)
134         */
135        @Override
136        public synchronized void setHttpClient(Object theHttpClient) {
137                this.myHttpClient = (HttpClient) theHttpClient;
138        }
139
140        @Override
141        public void setProxy(String theHost, Integer thePort) {
142                if (theHost != null) {
143                        myProxy = new HttpHost(theHost, thePort, "http");
144                } else {
145                        myProxy = null;
146                }
147        }
148
149}