001package io.freefair.spring.okhttp;
002
003import okhttp3.*;
004import org.springframework.beans.factory.ObjectProvider;
005import org.springframework.beans.factory.annotation.Autowired;
006import org.springframework.boot.autoconfigure.AutoConfigureAfter;
007import org.springframework.boot.autoconfigure.AutoConfigureBefore;
008import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
009import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
010import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
011import org.springframework.boot.context.properties.EnableConfigurationProperties;
012import org.springframework.context.annotation.Bean;
013import org.springframework.context.annotation.Configuration;
014import org.springframework.http.client.OkHttp3ClientHttpRequestFactory;
015
016import java.io.File;
017import java.io.IOException;
018import java.nio.file.Files;
019import java.time.Duration;
020import java.util.concurrent.TimeUnit;
021
022/**
023 * @author Lars Grefer
024 */
025@Configuration(proxyBeanMethods = false)
026@ConditionalOnClass(OkHttpClient.class)
027@EnableConfigurationProperties(OkHttpProperties.class)
028public class OkHttp3AutoConfiguration {
029
030    @Autowired
031    private OkHttpProperties okHttpProperties;
032
033    @Autowired
034    private ObjectProvider<Configurer<OkHttpClient.Builder>> configurers;
035
036    @Autowired
037    @ApplicationInterceptor
038    private ObjectProvider<Interceptor> applicationInterceptors;
039
040    @Autowired
041    @NetworkInterceptor
042    private ObjectProvider<Interceptor> networkInterceptors;
043
044    @Bean
045    @ConditionalOnMissingBean
046    public OkHttpClient okHttp3Client(
047            ObjectProvider<Cache> cache,
048            ObjectProvider<CookieJar> cookieJar,
049            ObjectProvider<Dns> dns,
050            ConnectionPool connectionPool
051    ) {
052        OkHttpClient.Builder builder = new OkHttpClient.Builder();
053
054        cache.ifUnique(builder::cache);
055
056        builder.connectTimeout(okHttpProperties.getConnectTimeout().toMillis(), TimeUnit.MILLISECONDS);
057        builder.readTimeout(okHttpProperties.getReadTimeout().toMillis(), TimeUnit.MILLISECONDS);
058        builder.writeTimeout(okHttpProperties.getWriteTimeout().toMillis(), TimeUnit.MILLISECONDS);
059        builder.pingInterval(okHttpProperties.getPingInterval().toMillis(), TimeUnit.MILLISECONDS);
060
061        cookieJar.ifUnique(builder::cookieJar);
062
063        dns.ifUnique(builder::dns);
064
065        builder.connectionPool(connectionPool);
066
067        builder.followRedirects(okHttpProperties.isFollowRedirects());
068        builder.followSslRedirects(okHttpProperties.isFollowSslRedirects());
069        builder.retryOnConnectionFailure(okHttpProperties.isRetryOnConnectionFailure());
070
071        applicationInterceptors.forEach(i -> builder.interceptors().add(i));
072
073        networkInterceptors.forEach(i -> builder.networkInterceptors().add(i));
074
075        configurers.forEach(configurer -> configurer.configure(builder));
076
077        return builder.build();
078    }
079
080    @Bean
081    @ConditionalOnMissingBean
082    public ConnectionPool okHttp3ConnectionPool() {
083        int maxIdleConnections = okHttpProperties.getConnectionPool().getMaxIdleConnections();
084        Duration keepAliveDuration = okHttpProperties.getConnectionPool().getKeepAliveDuration();
085        return new ConnectionPool(maxIdleConnections, keepAliveDuration.toNanos(), TimeUnit.NANOSECONDS);
086    }
087
088    @Bean
089    @ConditionalOnMissingBean
090    @ConditionalOnProperty(value = "okhttp.cache.enabled", havingValue = "true", matchIfMissing = true)
091    public Cache okHttp3Cache() throws IOException {
092        File directory = okHttpProperties.getCache().getDirectory();
093        if (directory == null) {
094            directory = Files.createTempDirectory("okhttp-cache").toFile();
095        }
096        return new Cache(directory, okHttpProperties.getCache().getMaxSize().toBytes());
097    }
098
099    /**
100     * @author Lars Grefer
101     */
102    @Configuration(proxyBeanMethods = false)
103    @ConditionalOnClass(OkHttp3ClientHttpRequestFactory.class)
104    @AutoConfigureBefore(OkHttpRestTemplateAutoConfiguration.class)
105    @AutoConfigureAfter(OkHttp3AutoConfiguration.class)
106    public static class RequestFactoryAutoConfiguration {
107
108        @Bean
109        @ConditionalOnMissingBean(OkHttp3ClientHttpRequestFactory.class)
110        public OkHttp3ClientHttpRequestFactory okHttp3ClientHttpRequestFactory(OkHttpClient okHttpClient) {
111            return new OkHttp3ClientHttpRequestFactory(okHttpClient);
112        }
113    }
114}