Skip to content

Commit f21b866

Browse files
swallezl-trotta
authored andcommitted
Allow extensions of ElasticsearchTransportConfig
1 parent 6304e32 commit f21b866

File tree

4 files changed

+243
-104
lines changed

4 files changed

+243
-104
lines changed

java-client/src/main/java/co/elastic/clients/transport/ElasticsearchTransportConfig.java

Lines changed: 179 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -32,17 +32,17 @@
3232
import java.util.List;
3333
import java.util.function.Function;
3434

35-
public class ElasticsearchTransportConfig {
36-
private List<URI> hosts;
37-
private String username;
38-
private String password;
39-
private String token;
40-
private String apiKey;
41-
private SSLContext sslContext;
42-
private JsonpMapper mapper;
43-
private TransportOptions transportOptions;
44-
private Instrumentation instrumentation;
45-
private Function<ElasticsearchTransportConfig, ElasticsearchTransport> transportFactory;
35+
public abstract class ElasticsearchTransportConfig {
36+
protected List<URI> hosts;
37+
protected String username;
38+
protected String password;
39+
protected String token;
40+
protected String apiKey;
41+
protected boolean useCompression = false;
42+
protected SSLContext sslContext;
43+
protected JsonpMapper mapper;
44+
protected TransportOptions transportOptions;
45+
protected Instrumentation instrumentation;
4646

4747
public List<URI> hosts() {
4848
return hosts;
@@ -68,6 +68,10 @@ public String apiKey() {
6868
return apiKey;
6969
}
7070

71+
public boolean useCompression() {
72+
return useCompression;
73+
}
74+
7175
@Nullable
7276
public SSLContext sslContext() {
7377
return sslContext;
@@ -86,150 +90,245 @@ public Instrumentation instrumentation() {
8690
return instrumentation;
8791
}
8892

89-
public Function<ElasticsearchTransportConfig, ElasticsearchTransport> transportFactory() {
90-
return transportFactory;
93+
public abstract ElasticsearchTransport buildTransport();
94+
95+
//---------------------------------------------------------------------------------------------
96+
97+
/**
98+
* Default configuration that can be used with any transport implementation. If no transport
99+
* factory is defined with {@link #transportFactory}, a {@link Rest5ClientTransport} is used.
100+
*/
101+
public static class Default extends ElasticsearchTransportConfig {
102+
103+
protected Function<ElasticsearchTransportConfig, ElasticsearchTransport> transportFactory;
104+
105+
public Function<ElasticsearchTransportConfig, ElasticsearchTransport> transportFactory() {
106+
return transportFactory;
107+
}
108+
109+
public ElasticsearchTransport buildTransport() {
110+
return this.transportFactory.apply(this);
111+
}
91112
}
92113

93-
public ElasticsearchTransport buildTransport() {
94-
return this.transportFactory.apply(this);
114+
/**
115+
* Builder for {@link Default} transport configurations.
116+
*/
117+
public static class Builder extends ElasticsearchTransportConfig.AbstractBuilder<Builder> {
118+
private final Default dconfig;
119+
120+
public Builder() {
121+
this(new Default());
122+
}
123+
124+
private Builder(Default dconfig) {
125+
super(dconfig);
126+
// Typed accessor to this.config
127+
this.dconfig = dconfig;
128+
}
129+
130+
@Override
131+
protected Builder self() {
132+
return this;
133+
}
134+
135+
/**
136+
* Should we use the legacy http implementation based on Elasticsearch's Low Level Rest Client?
137+
* <p>
138+
* Shortcut for {@code transportFactory(RestClientTransport::new)}.
139+
*
140+
* @see RestClientTransport
141+
*/
142+
public Builder useLegacyTransport(boolean useLegacyTransport) {
143+
if (useLegacyTransport) {
144+
dconfig.transportFactory = RestClientTransport::new;
145+
} else {
146+
dconfig.transportFactory = null;
147+
}
148+
return this;
149+
}
150+
151+
/**
152+
* Defines the factory function to create a transport with this configuration.
153+
*
154+
* @see #buildTransport()
155+
*/
156+
public Builder transportFactory(Function<ElasticsearchTransportConfig, ElasticsearchTransport> factory) {
157+
dconfig.transportFactory = factory;
158+
return this;
159+
}
160+
161+
@Override
162+
public Default build() {
163+
Default config = (Default) super.build();
164+
165+
// Default transport implementation
166+
if (config.transportFactory == null) {
167+
config.transportFactory = Rest5ClientTransport::new;
168+
}
169+
170+
return config;
171+
}
95172
}
96173

97174
//---------------------------------------------------------------------------------------------
98175

99-
public static class Builder {
176+
public abstract static class AbstractBuilder<BuilderT extends AbstractBuilder<BuilderT>> {
177+
protected final ElasticsearchTransportConfig config;
178+
179+
public AbstractBuilder(ElasticsearchTransportConfig config) {
180+
this.config = config;
181+
}
182+
183+
protected abstract BuilderT self();
184+
185+
protected ElasticsearchTransportConfig build() {
186+
187+
//---- Validate credentials
188+
189+
if (config.username != null) {
190+
checkNull(config.token, "token", "username/password");
191+
checkNull(config.apiKey, "API key", "username/password");
192+
if (config.password == null) {
193+
throw new IllegalArgumentException("password required with username");
194+
}
195+
} else if (config.password != null) {
196+
throw new IllegalArgumentException("username required with password");
197+
}
198+
199+
if (config.token != null) {
200+
checkNull(config.apiKey, "API key", "token");
201+
checkNull(config.username, "username", "token");
202+
}
203+
204+
if (config.apiKey != null) {
205+
checkNull(config.token, "token", "API key");
206+
checkNull(config.username, "username", "API key");
207+
}
100208

101-
public final ElasticsearchTransportConfig config = new ElasticsearchTransportConfig();
209+
//---- Validate other settings
102210

103-
public ElasticsearchTransportConfig build() {
104211
if (config.hosts() == null || config.hosts.isEmpty()) {
105-
throw new IllegalStateException("hosts cannot be empty");
212+
throw new IllegalArgumentException("hosts cannot be empty");
106213
}
107214

108215
if (config.mapper == null) {
109216
config.mapper = new JacksonJsonpMapper();
110217
}
111218

112-
if (config.transportFactory == null) {
113-
config.transportFactory = Rest5ClientTransport::new;
114-
}
115-
116219
return config;
117-
}
220+
};
118221

119-
public Builder host(String url) {
222+
/**
223+
* Elasticsearch host location
224+
*/
225+
public BuilderT host(String url) {
120226
try {
121227
config.hosts = List.of(new URI(url));
122228
} catch (URISyntaxException e) {
123229
// Avoid requiring a checked exception in the builder
124230
throw new RuntimeException(e);
125231
}
126-
return this;
232+
return self();
127233
}
128234

129-
public Builder host(URI url) {
235+
/**
236+
* Elasticsearch host location
237+
*/
238+
public BuilderT host(URI url) {
130239
config.hosts = List.of(url);
131-
return this;
240+
return self();
132241
}
133242

134-
public Builder hosts(List<URI> hosts) {
243+
/**
244+
* Elasticsearch hosts locations
245+
*/
246+
public BuilderT hosts(List<URI> hosts) {
135247
config.hosts = hosts;
136-
return this;
248+
return self();
137249
}
138250

139251
/**
140252
* Set the username and password to use to connect to Elasticsearch.
141253
*/
142-
public Builder usernameAndPassword(String username, String password) {
143-
checkNull(config.token, "token", "username/password");
144-
checkNull(config.apiKey, "API key", "username/password");
254+
public BuilderT usernameAndPassword(String username, String password) {
145255
config.username = username;
146256
config.password = password;
147-
return this;
257+
return self();
148258
}
149259

150260
/**
151261
* Set the bearer token to use to authenticate to Elasticsearch.
152262
*/
153-
public Builder token(String token) {
154-
checkNull(config.apiKey, "API key", "token");
155-
checkNull(config.username, "username", "token");
263+
public BuilderT token(String token) {
156264
config.token = token;
157-
return this;
265+
return self();
158266
}
159267

160268
/**
161269
* Set the API key to use to authenticate to Elasticsearch.
162270
*/
163-
public Builder apiKey(String apiKey) {
164-
checkNull(config.token, "token", "API key");
165-
checkNull(config.username, "username", "API key");
271+
public BuilderT apiKey(String apiKey) {
166272
config.apiKey = apiKey;
167-
return this;
273+
return self();
168274
}
169275

170276
/**
171-
* Set the SSL context. See {@link co.elastic.clients.transport.TransportUtils} to create it
172-
* from certificate files or a certificate fingerprint.
277+
* Should request and response body compression be used?
278+
*/
279+
public BuilderT useCompression(boolean useCompression) {
280+
this.config.useCompression = useCompression;
281+
return self();
282+
}
283+
284+
/**
285+
* SSL context to use for https connections. See {@link co.elastic.clients.transport.TransportUtils} to create it
286+
* from a certificate file or a certificate fingerprint.
173287
*
174288
* @see co.elastic.clients.transport.TransportUtils
175289
*/
176-
public Builder sslContext(SSLContext sslContext) {
290+
public BuilderT sslContext(SSLContext sslContext) {
177291
config.sslContext = sslContext;
178-
return this;
179-
}
180-
181-
public Builder setHosts(List<URI> hosts) {
182-
config.hosts = hosts;
183-
return this;
292+
return self();
184293
}
185294

186295
/**
187-
* Set the JSON mapper.
296+
* The JSON mapper to use. Defaults to {@link JacksonJsonpMapper}.
188297
*/
189-
public Builder jsonMapper(JsonpMapper mapper) {
298+
public BuilderT jsonMapper(JsonpMapper mapper) {
190299
config.mapper = mapper;
191-
return this;
300+
return self();
192301
}
193302

194-
public Builder instrumentation(Instrumentation instrumentation) {
303+
/**
304+
* Transport instrumentation to log client traffic. See
305+
* {@link co.elastic.clients.transport.instrumentation.OpenTelemetryForElasticsearch} for OpenTelemetry integration.
306+
*/
307+
public BuilderT instrumentation(Instrumentation instrumentation) {
195308
config.instrumentation = instrumentation;
196-
return this;
309+
return self();
197310
}
198311

199-
public Builder transportOptions(TransportOptions transportOptions) {
312+
/**
313+
* Lower level transport options.
314+
*/
315+
public BuilderT transportOptions(TransportOptions transportOptions) {
200316
config.transportOptions = transportOptions;
201-
return this;
317+
return self();
202318
}
203319

204320
/**
205-
* Sets lower level transport options. This method <em>adds</em> options to the ones already set, if any.
321+
* Lower level transport options. This method <em>adds</em> options to the ones already set, if any.
206322
*/
207-
public Builder transportOptions(Function<TransportOptions.Builder, TransportOptions.Builder> fn) {
323+
public BuilderT transportOptions(Function<TransportOptions.Builder, TransportOptions.Builder> fn) {
208324
var builder = config.transportOptions == null ? new DefaultTransportOptions.Builder() : config.transportOptions.toBuilder();
209325
config.transportOptions = fn.apply(builder).build();
210-
return this;
211-
}
212-
213-
public Builder transportFactory(Function<ElasticsearchTransportConfig, ElasticsearchTransport> factory) {
214-
config.transportFactory = factory;
215-
return this;
216-
}
217-
218-
/**
219-
* Should we use the legacy http implementation based on Elasticsearch's Low Level Rest Client?
220-
*/
221-
public Builder useLegacyTransport(boolean useLegacyTransport) {
222-
if (useLegacyTransport) {
223-
config.transportFactory = RestClientTransport.FACTORY;
224-
} else {
225-
config.transportFactory = null;
226-
}
227-
return this;
326+
return self();
228327
}
229328

230-
private void checkNull(Object value, String name, String other) {
329+
protected void checkNull(Object value, String name, String other) {
231330
if (value != null) {
232-
throw new IllegalStateException("Cannot set both " + other + " and " + name + ".");
331+
throw new IllegalArgumentException("Cannot set both " + other + " and " + name + ".");
233332
}
234333
}
235334
}

java-client/src/main/java/co/elastic/clients/transport/rest5_client/Rest5ClientTransport.java

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
package co.elastic.clients.transport.rest5_client;
2121

2222
import co.elastic.clients.json.JsonpMapper;
23-
import co.elastic.clients.transport.ElasticsearchTransport;
2423
import co.elastic.clients.transport.ElasticsearchTransportBase;
2524
import co.elastic.clients.transport.Transport;
2625
import co.elastic.clients.transport.ElasticsearchTransportConfig;
@@ -33,15 +32,9 @@
3332

3433
import javax.annotation.Nullable;
3534
import java.util.Base64;
36-
import java.util.function.Function;
3735

3836
public class Rest5ClientTransport extends ElasticsearchTransportBase {
3937

40-
/**
41-
* Factory function to be used for {@link ElasticsearchTransportConfig#transportFactory()}.
42-
*/
43-
public static final Function<ElasticsearchTransportConfig, ElasticsearchTransport> FACTORY = Rest5ClientTransport::new;
44-
4538
private final Rest5Client restClient;
4639

4740
public Rest5ClientTransport(ElasticsearchTransportConfig config) {
@@ -90,6 +83,8 @@ private static Rest5Client buildRest5Client(ElasticsearchTransportConfig config)
9083
restClientBuilder.setSSLContext(config.sslContext());
9184
}
9285

86+
restClientBuilder.setCompressionEnabled(config.useCompression());
87+
9388
return restClientBuilder.build();
9489
}
9590

0 commit comments

Comments
 (0)