aboutsummaryrefslogtreecommitdiffstats
path: root/vespa-http-client/src/main/java/com/yahoo/vespa/http/client/config/ConnectionParams.java
blob: 9e34d4d17470418859e33d0af3a86db0d260d814 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.http.client.config;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.google.common.annotations.Beta;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import net.jcip.annotations.Immutable;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * Parameters given to a {@link com.yahoo.vespa.http.client.SessionFactory}
 * when creating {@link com.yahoo.vespa.http.client.Session}s. The parameters
 * contained in this class are related to the connections from the node running
 * the Session to the Vespa clusters.
 * This class is immutable
 * and has no public constructor - to instantiate one, use a {@link Builder}.
 *
 * @author Einar M R Rosenvinge
 */
@Immutable
public final class ConnectionParams {

    /**
     * Builder for {@link ConnectionParams}.
     */
    public static final class Builder {
        private SSLContext sslContext = null;
        private HostnameVerifier hostnameVerifier = SSLConnectionSocketFactory.getDefaultHostnameVerifier();
        private long connectionTimeout = TimeUnit.SECONDS.toMillis(60);
        private final Multimap<String, String> headers = ArrayListMultimap.create();
        private final Map<String, HeaderProvider> headerProviders = new HashMap<>();
        private int numPersistentConnectionsPerEndpoint = 8;
        private String proxyHost = null;
        private int proxyPort = 8080;
        private boolean useCompression = false;
        private int maxRetries = 100;
        private long minTimeBetweenRetriesMs = 700;
        private boolean dryRun = false;
        private int traceLevel = 0;
        private int traceEveryXOperation = 0;
        private boolean printTraceToStdErr = true;

        /**
         * Sets the SSLContext for the connection to the gateway when SSL is enabled for Endpoint.
         * Default null (no ssl). See also Endpoint configuration.
         *
         * @param sslContext sslContext for connection to gateway.
         * @return pointer to builder.
         */
        public Builder setSslContext(SSLContext sslContext) {
            this.sslContext = sslContext;
            return this;
        }

        /**
         * Sets the {@link HostnameVerifier} for the connection to the gateway when SSL is enabled for Endpoint.
         * Defaults to instance returned by {@link SSLConnectionSocketFactory#getDefaultHostnameVerifier()}.
         *
         * @param hostnameVerifier hostname verifier for connection to gateway.
         * @return pointer to builder.
         */
        public Builder setHostnameVerifier(HostnameVerifier hostnameVerifier) {
            this.hostnameVerifier = hostnameVerifier;
            return this;
        }

        /**
         * Set custom headers to be used
         *
         * @param key header name
         * @param value header value
         * @return pointer to builder.
         */
        public Builder addHeader(String key, String value) {
            headers.put(key, value);
            return this;
        }

        /**
         * Adds a header provider for dynamic headers; headers where the value may change during a feeding session
         * (e.g. security tokens with limited life time). Only one {@link HeaderProvider} is allowed for a given header name.
         *
         * @param provider A provider for a dynamic header
         * @return pointer to builder.
         * @throws IllegalArgumentException if a provider is already registered for the given header name
         */
        public Builder addDynamicHeader(String headerName, HeaderProvider provider) {
            Objects.requireNonNull(headerName, "Header name cannot be null");
            Objects.requireNonNull(provider, "Header provider cannot be null");
            if (headerProviders.containsKey(headerName)) {
                throw new IllegalArgumentException("Provider already registered for name '" + headerName + "'");
            }
            headerProviders.put(headerName, provider);
            return this;
        }

        /**
         * The number of connections between the http client and the gateways. A very low number can result
         * in the network not fully utilized and the round-trip time can be a limiting factor. A low number
         * can cause skew in distribution of load between gateways. A too high number will cause
         * many threads to run, more context switching and potential more memory usage. We recommend using about
         * 16 connections per gateway.
         *
         * @param numPersistentConnectionsPerEndpoint number of channels per endpoint
         * @return pointer to builder.
         */
        public Builder setNumPersistentConnectionsPerEndpoint(int numPersistentConnectionsPerEndpoint) {
            this.numPersistentConnectionsPerEndpoint = numPersistentConnectionsPerEndpoint;
            return this;
        }

        /**
         * Sets the HTTP proxy host name to use.
         *
         * @param proxyHost host name for proxy.
         * @return pointer to builder.
         */
        public Builder setProxyHost(String proxyHost) {
            this.proxyHost = proxyHost;
            return this;
        }

        /**
         * Sets the HTTP proxy host port to use.
         *
         * @param proxyPort host port for proxy.
         * @return pointer to builder.
         */
        public Builder setProxyPort(int proxyPort) {
            this.proxyPort = proxyPort;
            return this;
        }

        /**
         * Set whether compression of document operations during communication to server should be enabled.
         *
         * @param useCompression true if compression should be enabled.
         * @return pointer to builder.
         */
        public Builder setUseCompression(boolean useCompression) {
            this.useCompression = useCompression;
            return this;
        }

        /**
         * Set how many times to retry sending an operation to a gateway when encountering transient problems.
         *
         * @param maxRetries max number of retries
         * @return pointer to builder.
         */
        public Builder setMaxRetries(int maxRetries) {
            this.maxRetries = maxRetries;
            return this;
        }

        /**
         * Don't send data to gateway, just pretend that everything is fine.
         *
         * @param dryRun true if enabled.
         * @return pointer to builder.
         */
        public Builder setDryRun(boolean dryRun) {
            this.dryRun = dryRun;
            return this;
        }

        /**
         * Set the min time between retries when temporarily failing against a gateway.
         *
         * @param minTimeBetweenRetries the min time value
         * @param unit                  the unit of the min time.
         * @return pointer to builder.
         */
        public Builder setMinTimeBetweenRetries(long minTimeBetweenRetries, TimeUnit unit) {
            this.minTimeBetweenRetriesMs = unit.toMillis(minTimeBetweenRetries);
            return this;
        }

        public long getMinTimeBetweenRetriesMs() {
            return minTimeBetweenRetriesMs;
        }

        /**
         * Sets the trace level for tracing messagebus. 0 means to tracing.
         *
         * @param traceLevel tracelevel, larger value means more tracing.
         * @return pointer to builder.
         */
        public Builder setTraceLevel(int traceLevel) {
            this.traceLevel = traceLevel;
            return this;
        }

        /**
         * How often to trace messages in client. Please note that this does not affect tracing with messagebus
         *
         * @param traceEveryXOperation if zero, no tracing, 1 = every message, and so on.
         * @return pointer to builder.
         */
        public Builder setTraceEveryXOperation(int traceEveryXOperation) {
            this.traceEveryXOperation = traceEveryXOperation;
            return this;
        }

        /**
         * If enabled will write internal trace to stderr.
         *
         * @param printTraceToStdErr if value is true it is enabled.
         * @return pointer to builder.
         */
        public Builder setPrintTraceToStdErr(boolean printTraceToStdErr) {
            this.printTraceToStdErr = printTraceToStdErr;
            return this;
        }


        public ConnectionParams build() {
            return new ConnectionParams(
                    sslContext,
                    hostnameVerifier,
                    connectionTimeout,
                    headers,
                    headerProviders,
                    numPersistentConnectionsPerEndpoint,
                    proxyHost,
                    proxyPort,
                    useCompression,
                    maxRetries,
                    minTimeBetweenRetriesMs,
                    dryRun,
                    traceLevel,
                    traceEveryXOperation,
                    printTraceToStdErr);
        }

        public int getNumPersistentConnectionsPerEndpoint() {
            return numPersistentConnectionsPerEndpoint;
        }

        public String getProxyHost() {
            return proxyHost;
        }

        public boolean isDryRun() {
            return dryRun;
        }

        public int getMaxRetries() {
            return maxRetries;
        }
        public int getTraceLevel() {
            return traceLevel;
        }
        public int getTraceEveryXOperation() {
            return traceEveryXOperation;
        }

        public boolean getPrintTraceToStdErr() {
            return printTraceToStdErr;
        }

        public int getProxyPort() {
            return proxyPort;
        }

        public SSLContext getSslContext() {
            return sslContext;
        }

        public HostnameVerifier getHostnameVerifier() {
            return hostnameVerifier;
        }
    }
    private final SSLContext sslContext;
    private final HostnameVerifier hostnameVerifier;
    private final long connectionTimeout;
    private final Multimap<String, String> headers = ArrayListMultimap.create();
    private final Map<String, HeaderProvider> headerProviders = new HashMap<>();
    private final int numPersistentConnectionsPerEndpoint;
    private final String proxyHost;
    private final int proxyPort;
    private final boolean useCompression;
    private final int maxRetries;
    private final long minTimeBetweenRetriesMs;
    private final boolean dryRun;
    private final int traceLevel;
    private final int traceEveryXOperation;
    private final boolean printTraceToStdErr;

    private ConnectionParams(
            SSLContext sslContext,
            HostnameVerifier hostnameVerifier,
            long connectionTimeout,
            Multimap<String, String> headers,
            Map<String, HeaderProvider> headerProviders,
            int numPersistentConnectionsPerEndpoint,
            String proxyHost,
            int proxyPort,
            boolean useCompression,
            int maxRetries,
            long minTimeBetweenRetriesMs,
            boolean dryRun,
            int traceLevel,
            int traceEveryXOperation,
            boolean printTraceToStdErr) {
        this.sslContext = sslContext;
        this.hostnameVerifier = hostnameVerifier;
        this.connectionTimeout = connectionTimeout;
        this.headers.putAll(headers);
        this.headerProviders.putAll(headerProviders);
        this.numPersistentConnectionsPerEndpoint = numPersistentConnectionsPerEndpoint;
        this.proxyHost = proxyHost;
        this.proxyPort = proxyPort;
        this.useCompression = useCompression;
        this.maxRetries = maxRetries;
        this.minTimeBetweenRetriesMs = minTimeBetweenRetriesMs;
        this.dryRun = dryRun;
        this.traceLevel = traceLevel;
        this.traceEveryXOperation = traceEveryXOperation;
        this.printTraceToStdErr = printTraceToStdErr;
    }

    @JsonIgnore
    public SSLContext getSslContext() {
        return sslContext;
    }

    @JsonIgnore
    public HostnameVerifier getHostnameVerifier() {
        return hostnameVerifier;
    }

    public Collection<Map.Entry<String, String>> getHeaders() {
        return Collections.unmodifiableCollection(headers.entries());
    }

    public Map<String, HeaderProvider> getDynamicHeaders() {
        return Collections.unmodifiableMap(headerProviders);
    }

    public int getNumPersistentConnectionsPerEndpoint() {
        return numPersistentConnectionsPerEndpoint;
    }

    public String getProxyHost() {
        return proxyHost;
    }

    public int getProxyPort() {
        return proxyPort;
    }

    public boolean getUseCompression() {
        return useCompression;
    }

    public int getMaxRetries() {
        return maxRetries;
    }

    public long getMinTimeBetweenRetriesMs() {
        return minTimeBetweenRetriesMs;
    }

    public boolean isDryRun() {
        return dryRun;
    }

    public int getTraceLevel() {
        return traceLevel;
    }

    public int getTraceEveryXOperation() {
        return traceEveryXOperation;
    }

    public boolean getPrintTraceToStdErr() {
        return printTraceToStdErr;
    }

    /**
     * A header provider that provides a header value. {@link #getHeaderValue()} is called each time a new HTTP request
     * is constructed by {@link com.yahoo.vespa.http.client.FeedClient}.
     *
     * Important: The implementation of {@link #getHeaderValue()} must be thread-safe!
     */
    public interface HeaderProvider {
        String getHeaderValue();
    }

}