0
# Connectors and SPI
1
2
Service Provider Interface for pluggable HTTP transport connectors and extensibility hooks including custom connectors, request/response interceptors, client lifecycle listeners, and async callback mechanisms. This functionality enables deep customization and integration with different HTTP client implementations.
3
4
## Capabilities
5
6
### Connector Provider Interface
7
8
Core interface for providing HTTP transport connectors that handle the actual HTTP communication.
9
10
```java { .api }
11
/**
12
* Contract for providing client transport connectors
13
*/
14
public interface ConnectorProvider {
15
/**
16
* Create connector instance for the given client and configuration
17
* @param client client instance requesting the connector
18
* @param runtimeConfig runtime configuration for the connector
19
* @return configured connector instance
20
*/
21
Connector getConnector(Client client, Configuration runtimeConfig);
22
}
23
```
24
25
### Connector Interface
26
27
Core connector interface that handles HTTP request execution with support for both synchronous and asynchronous operations.
28
29
```java { .api }
30
/**
31
* Client transport connector for executing HTTP requests
32
*/
33
public interface Connector extends Inflector<ClientRequest, ClientResponse> {
34
/**
35
* Execute HTTP request synchronously
36
* @param request client request to execute
37
* @return client response
38
*/
39
ClientResponse apply(ClientRequest request);
40
41
/**
42
* Execute HTTP request asynchronously
43
* @param request client request to execute
44
* @param callback callback for handling response or failure
45
* @return Future representing the async operation
46
*/
47
Future<?> apply(ClientRequest request, AsyncConnectorCallback callback);
48
49
/**
50
* Get connector name for identification
51
* @return connector name
52
*/
53
String getName();
54
55
/**
56
* Close connector and release resources
57
*/
58
void close();
59
}
60
```
61
62
### Async Connector Callback
63
64
Callback interface for handling asynchronous HTTP request results and failures.
65
66
```java { .api }
67
/**
68
* Callback interface for asynchronous connector operations
69
*/
70
public interface AsyncConnectorCallback {
71
/**
72
* Handle successful response
73
* @param response client response from successful request
74
*/
75
void response(ClientResponse response);
76
77
/**
78
* Handle request failure
79
* @param failure throwable representing the failure cause
80
*/
81
void failure(Throwable failure);
82
}
83
```
84
85
### HTTP URL Connector Provider
86
87
Default connector provider implementation using Java's built-in HttpURLConnection for HTTP transport.
88
89
```java { .api }
90
public class HttpUrlConnectorProvider implements ConnectorProvider {
91
// Configuration properties
92
public static final String USE_FIXED_LENGTH_STREAMING = "jersey.config.client.httpUrlConnector.useFixedLengthStreaming";
93
public static final String SET_METHOD_WORKAROUND = "jersey.config.client.httpUrlConnector.setMethodWorkaround";
94
95
/**
96
* Create default HTTP URL connector provider
97
*/
98
public HttpUrlConnectorProvider();
99
100
/**
101
* Configure connector with custom connection factory
102
* @param connectionFactory factory for creating HTTP connections
103
* @return configured connector provider
104
*/
105
public HttpUrlConnectorProvider connectionFactory(ConnectionFactory connectionFactory);
106
107
/**
108
* Configure chunk size for chunked encoding
109
* @param chunkSize chunk size in bytes
110
* @return configured connector provider
111
*/
112
public HttpUrlConnectorProvider chunkSize(int chunkSize);
113
114
/**
115
* Enable fixed-length streaming mode
116
* @return configured connector provider
117
*/
118
public HttpUrlConnectorProvider useFixedLengthStreaming();
119
120
/**
121
* Enable HTTP method workaround for restricted methods
122
* @return configured connector provider
123
*/
124
public HttpUrlConnectorProvider useSetMethodWorkaround();
125
126
/**
127
* Create connector instance
128
* @param client client instance
129
* @param config runtime configuration
130
* @return HTTP URL connector instance
131
*/
132
public Connector getConnector(Client client, Configuration config);
133
}
134
```
135
136
### Connection Factory
137
138
Factory interface for creating HTTP URL connections with optional proxy support.
139
140
```java { .api }
141
/**
142
* Factory for creating HTTP URL connections
143
*/
144
public interface ConnectionFactory {
145
/**
146
* Create HTTP connection for the given URL
147
* @param url target URL for connection
148
* @return HTTP URL connection
149
* @throws IOException if connection creation fails
150
*/
151
HttpURLConnection getConnection(URL url) throws IOException;
152
153
/**
154
* Create HTTP connection for the given URL with proxy
155
* @param url target URL for connection
156
* @param proxy proxy for connection
157
* @return HTTP URL connection
158
* @throws IOException if connection creation fails
159
*/
160
default HttpURLConnection getConnection(URL url, Proxy proxy) throws IOException {
161
return getConnection(url);
162
}
163
}
164
```
165
166
**Usage Examples:**
167
168
```java
169
import org.glassfish.jersey.client.HttpUrlConnectorProvider;
170
import java.net.HttpURLConnection;
171
import java.net.URL;
172
import java.net.Proxy;
173
174
// Custom connection factory
175
HttpUrlConnectorProvider.ConnectionFactory customFactory = new HttpUrlConnectorProvider.ConnectionFactory() {
176
@Override
177
public HttpURLConnection getConnection(URL url) throws IOException {
178
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
179
connection.setConnectTimeout(10000);
180
connection.setReadTimeout(30000);
181
return connection;
182
}
183
184
@Override
185
public HttpURLConnection getConnection(URL url, Proxy proxy) throws IOException {
186
HttpURLConnection connection = (HttpURLConnection) url.openConnection(proxy);
187
connection.setConnectTimeout(10000);
188
connection.setReadTimeout(30000);
189
return connection;
190
}
191
};
192
193
// Configure client with custom connector
194
HttpUrlConnectorProvider connectorProvider = new HttpUrlConnectorProvider()
195
.connectionFactory(customFactory)
196
.chunkSize(8192)
197
.useFixedLengthStreaming();
198
199
ClientConfig config = new ClientConfig();
200
config.connectorProvider(connectorProvider);
201
Client client = JerseyClientBuilder.createClient(config);
202
```
203
204
### Caching Connector Provider
205
206
Caching wrapper for connector providers that reuses connector instances for improved performance.
207
208
```java { .api }
209
public class CachingConnectorProvider implements ConnectorProvider {
210
/**
211
* Create caching wrapper for the given connector provider
212
* @param delegate underlying connector provider to cache
213
*/
214
public CachingConnectorProvider(ConnectorProvider delegate);
215
216
/**
217
* Get connector instance (cached if previously created)
218
* @param client client instance
219
* @param runtimeConfig runtime configuration
220
* @return cached or new connector instance
221
*/
222
public Connector getConnector(Client client, Configuration runtimeConfig);
223
}
224
```
225
226
**Usage Examples:**
227
228
```java
229
// Wrap any connector provider with caching
230
ConnectorProvider baseProvider = new HttpUrlConnectorProvider();
231
ConnectorProvider cachingProvider = new CachingConnectorProvider(baseProvider);
232
233
ClientConfig config = new ClientConfig();
234
config.connectorProvider(cachingProvider);
235
Client client = JerseyClientBuilder.createClient(config);
236
```
237
238
### Client Builder Listener
239
240
Listener interface for intercepting client builder creation events.
241
242
```java { .api }
243
/**
244
* Listener for client builder creation events
245
*/
246
public interface ClientBuilderListener {
247
/**
248
* Called when a new client builder is created
249
* @param builder newly created client builder
250
*/
251
void onNewBuilder(ClientBuilder builder);
252
}
253
```
254
255
### Invocation Builder Listener
256
257
Listener interface for intercepting invocation builder creation events.
258
259
```java { .api }
260
/**
261
* Listener for invocation builder creation events
262
*/
263
public interface InvocationBuilderListener {
264
/**
265
* Called when a new invocation builder is created
266
* @param builder newly created invocation builder
267
* @param config configuration associated with the builder
268
*/
269
void onNewBuilder(Invocation.Builder builder, Configuration config);
270
}
271
```
272
273
### Pre-Invocation Interceptor
274
275
Interceptor interface for processing requests before they are executed.
276
277
```java { .api }
278
/**
279
* Interceptor for pre-request processing
280
*/
281
public interface PreInvocationInterceptor {
282
/**
283
* Called before request execution
284
* @param requestContext client request context for modification
285
*/
286
void beforeRequest(ClientRequestContext requestContext);
287
}
288
```
289
290
### Post-Invocation Interceptor
291
292
Interceptor interface for processing requests after they are executed or when exceptions occur.
293
294
```java { .api }
295
/**
296
* Interceptor for post-request processing
297
*/
298
public interface PostInvocationInterceptor {
299
/**
300
* Called after successful request execution
301
* @param requestContext client request context
302
* @param responseContext client response context
303
*/
304
void afterRequest(ClientRequestContext requestContext, ClientResponseContext responseContext);
305
306
/**
307
* Called when request execution fails with exception
308
* @param requestContext client request context
309
* @param exceptionContext exception context with failure details
310
*/
311
void onException(ClientRequestContext requestContext, ExceptionContext exceptionContext);
312
}
313
```
314
315
**Usage Examples:**
316
317
```java
318
// Custom pre-invocation interceptor for logging
319
public class LoggingPreInterceptor implements PreInvocationInterceptor {
320
@Override
321
public void beforeRequest(ClientRequestContext requestContext) {
322
System.out.println("Executing request: " +
323
requestContext.getMethod() + " " + requestContext.getUri());
324
325
// Add custom headers
326
requestContext.getHeaders().add("X-Request-ID", generateRequestId());
327
requestContext.getHeaders().add("X-Client-Version", "1.0.0");
328
}
329
}
330
331
// Custom post-invocation interceptor for metrics
332
public class MetricsPostInterceptor implements PostInvocationInterceptor {
333
@Override
334
public void afterRequest(ClientRequestContext requestContext,
335
ClientResponseContext responseContext) {
336
long duration = System.currentTimeMillis() - getRequestStartTime(requestContext);
337
recordMetrics(requestContext.getMethod(),
338
responseContext.getStatus(),
339
duration);
340
}
341
342
@Override
343
public void onException(ClientRequestContext requestContext,
344
ExceptionContext exceptionContext) {
345
recordFailure(requestContext.getMethod(),
346
exceptionContext.getThrowable().getClass().getSimpleName());
347
}
348
}
349
350
// Register interceptors with client
351
Client client = JerseyClientBuilder.createClient()
352
.register(new LoggingPreInterceptor())
353
.register(new MetricsPostInterceptor());
354
```
355
356
### Custom Connector Implementation
357
358
Example of implementing a custom connector for specialized HTTP transport needs.
359
360
**Usage Examples:**
361
362
```java
363
// Custom connector implementation
364
public class CustomHttpConnector implements Connector {
365
private final String name;
366
private final HttpClient httpClient; // Your preferred HTTP client
367
368
public CustomHttpConnector(String name, HttpClient httpClient) {
369
this.name = name;
370
this.httpClient = httpClient;
371
}
372
373
@Override
374
public ClientResponse apply(ClientRequest request) {
375
try {
376
// Convert Jersey ClientRequest to your HTTP client request
377
HttpRequest httpRequest = convertRequest(request);
378
379
// Execute request
380
HttpResponse httpResponse = httpClient.execute(httpRequest);
381
382
// Convert response back to Jersey ClientResponse
383
return convertResponse(httpResponse);
384
} catch (Exception e) {
385
throw new ProcessingException("Request execution failed", e);
386
}
387
}
388
389
@Override
390
public Future<?> apply(ClientRequest request, AsyncConnectorCallback callback) {
391
return CompletableFuture.runAsync(() -> {
392
try {
393
ClientResponse response = apply(request);
394
callback.response(response);
395
} catch (Exception e) {
396
callback.failure(e);
397
}
398
});
399
}
400
401
@Override
402
public String getName() {
403
return name;
404
}
405
406
@Override
407
public void close() {
408
if (httpClient != null) {
409
httpClient.close();
410
}
411
}
412
413
private HttpRequest convertRequest(ClientRequest clientRequest) {
414
// Implementation details for request conversion
415
return null;
416
}
417
418
private ClientResponse convertResponse(HttpResponse httpResponse) {
419
// Implementation details for response conversion
420
return null;
421
}
422
}
423
424
// Custom connector provider
425
public class CustomHttpConnectorProvider implements ConnectorProvider {
426
private final HttpClient httpClient;
427
428
public CustomHttpConnectorProvider(HttpClient httpClient) {
429
this.httpClient = httpClient;
430
}
431
432
@Override
433
public Connector getConnector(Client client, Configuration runtimeConfig) {
434
return new CustomHttpConnector("custom-http", httpClient);
435
}
436
}
437
438
// Use custom connector
439
HttpClient customHttpClient = createCustomHttpClient();
440
ConnectorProvider customProvider = new CustomHttpConnectorProvider(customHttpClient);
441
442
ClientConfig config = new ClientConfig();
443
config.connectorProvider(customProvider);
444
Client client = JerseyClientBuilder.createClient(config);
445
```
446
447
### Service Provider Integration
448
449
Integration with Java's ServiceLoader mechanism for automatic discovery of SPI implementations.
450
451
**Usage Examples:**
452
453
```java
454
// Service provider configuration (META-INF/services/org.glassfish.jersey.client.spi.ConnectorProvider)
455
// com.example.MyCustomConnectorProvider
456
457
// Automatic discovery and ranking
458
public class MyCustomConnectorProvider implements ConnectorProvider {
459
@Override
460
public Connector getConnector(Client client, Configuration runtimeConfig) {
461
return new MyCustomConnector();
462
}
463
}
464
465
// SPI implementations are automatically discovered and can be ranked using @Priority
466
@Priority(Priorities.USER)
467
public class HighPriorityConnectorProvider implements ConnectorProvider {
468
// Higher priority implementation
469
}
470
471
// Client will automatically use discovered implementations based on priority
472
Client client = JerseyClientBuilder.createClient(); // Uses discovered providers
473
```