3232import java .util .List ;
3333import 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 }
0 commit comments