001package ca.uhn.fhir.rest.client.apache;
002
003/*
004 * #%L
005 * HAPI FHIR - Client Framework
006 * %%
007 * Copyright (C) 2014 - 2019 University Health Network
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 java.util.List;
024import java.util.Map;
025import java.util.concurrent.TimeUnit;
026
027import org.apache.commons.lang3.StringUtils;
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 ca.uhn.fhir.context.FhirContext;
041import ca.uhn.fhir.rest.api.RequestTypeEnum;
042import ca.uhn.fhir.rest.client.api.Header;
043import ca.uhn.fhir.rest.client.api.IHttpClient;
044import ca.uhn.fhir.rest.client.impl.RestfulClientFactory;
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 ApacheHttpClient getHttpClient(String theServerBase) {
075                return new ApacheHttpClient(getNativeHttpClient(), new StringBuilder(theServerBase), null, null, null, null);
076        }
077
078        @Override
079        public 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,
082                                theHeaders);
083        }
084
085        public synchronized HttpClient getNativeHttpClient() {
086                if (myHttpClient == null) {
087
088                        //FIXME potential resoource leak
089                        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000,
090                                        TimeUnit.MILLISECONDS);
091                        connectionManager.setMaxTotal(getPoolMaxTotal());
092                        connectionManager.setDefaultMaxPerRoute(getPoolMaxPerRoute());
093
094                        // @formatter:off
095                        //TODO: Use of a deprecated method should be resolved.
096                        RequestConfig defaultRequestConfig =
097                                RequestConfig.custom()
098                                        .setSocketTimeout(getSocketTimeout())
099                                        .setConnectTimeout(getConnectTimeout())
100                                        .setConnectionRequestTimeout(getConnectionRequestTimeout())
101                                        .setStaleConnectionCheckEnabled(true)
102                                        .setProxy(myProxy)
103                                        .build();
104
105                        HttpClientBuilder builder = HttpClients.custom().setConnectionManager(connectionManager)
106                                        .setDefaultRequestConfig(defaultRequestConfig).disableCookieManagement();
107
108                        if (myProxy != null && StringUtils.isNotBlank(getProxyUsername()) && StringUtils.isNotBlank(getProxyPassword())) {
109                                CredentialsProvider credsProvider = new BasicCredentialsProvider();
110                                credsProvider.setCredentials(new AuthScope(myProxy.getHostName(), myProxy.getPort()),
111                                                new UsernamePasswordCredentials(getProxyUsername(), getProxyPassword()));
112                                builder.setProxyAuthenticationStrategy(new ProxyAuthenticationStrategy());
113                                builder.setDefaultCredentialsProvider(credsProvider);
114                        }
115
116                        myHttpClient = builder.build();
117                        // @formatter:on
118
119                }
120
121                return myHttpClient;
122        }
123
124        @Override
125        protected void resetHttpClient() {
126                this.myHttpClient = null;
127        }
128
129        /**
130         * Only allows to set an instance of type org.apache.http.client.HttpClient
131         * @see ca.uhn.fhir.rest.client.api.IRestfulClientFactory#setHttpClient(ca.uhn.fhir.rest.client.api.IHttpClient)
132         */
133        @Override
134        public synchronized void setHttpClient(Object theHttpClient) {
135                this.myHttpClient = (HttpClient) theHttpClient;
136        }
137
138        @Override
139        public void setProxy(String theHost, Integer thePort) {
140                if (theHost != null) {
141                        myProxy = new HttpHost(theHost, thePort, "http");
142                } else {
143                        myProxy = null;
144                }
145        }
146
147}