Skip to content

Commit f7fa2bf

Browse files
committed
feat: Provide a new http-client layer to create new HTTP client implementation / extensions (vertx)
1 parent 75b4150 commit f7fa2bf

File tree

58 files changed

+2329
-935
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+2329
-935
lines changed

README.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -349,13 +349,13 @@ Different transport protocols can be configured with specific settings using spe
349349

350350
##### JSON-RPC Transport Configuration
351351

352-
For the JSON-RPC transport, to use the default `JdkA2AHttpClient`, provide a `JSONRPCTransportConfig` created with its default constructor.
352+
For the JSON-RPC transport, to use the default `JdkHttpClient`, provide a `JSONRPCTransportConfig` created with its default constructor.
353353

354354
To use a custom HTTP client implementation, simply create a `JSONRPCTransportConfig` as follows:
355355

356356
```java
357-
// Create a custom HTTP client
358-
A2AHttpClient customHttpClient = ...
357+
// Create a custom HTTP client builder
358+
HttpClientBuilder httpClientBuilder = ...
359359

360360
// Configure the client settings
361361
ClientConfig clientConfig = new ClientConfig.Builder()
@@ -365,7 +365,7 @@ ClientConfig clientConfig = new ClientConfig.Builder()
365365
Client client = Client
366366
.builder(agentCard)
367367
.clientConfig(clientConfig)
368-
.withTransport(JSONRPCTransport.class, new JSONRPCTransportConfig(customHttpClient))
368+
.withTransport(JSONRPCTransport.class, new JSONRPCTransportConfig(httpClientBuilder))
369369
.build();
370370
```
371371

@@ -396,13 +396,13 @@ Client client = Client
396396

397397
##### HTTP+JSON/REST Transport Configuration
398398

399-
For the HTTP+JSON/REST transport, if you'd like to use the default `JdkA2AHttpClient`, provide a `RestTransportConfig` created with its default constructor.
399+
For the HTTP+JSON/REST transport, if you'd like to use the default `JdkHttpClient`, provide a `RestTransportConfig` created with its default constructor.
400400

401401
To use a custom HTTP client implementation, simply create a `RestTransportConfig` as follows:
402402

403403
```java
404404
// Create a custom HTTP client
405-
A2AHttpClient customHttpClient = ...
405+
HttpClientBuilder httpClientBuilder = ...
406406

407407
// Configure the client settings
408408
ClientConfig clientConfig = new ClientConfig.Builder()
@@ -412,7 +412,7 @@ ClientConfig clientConfig = new ClientConfig.Builder()
412412
Client client = Client
413413
.builder(agentCard)
414414
.clientConfig(clientConfig)
415-
.withTransport(RestTransport.class, new RestTransportConfig(customHttpClient))
415+
.withTransport(RestTransport.class, new RestTransportConfig(httpClientBuilder))
416416
.build();
417417
```
418418

client/base/src/main/java/io/a2a/A2A.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@
66
import java.util.UUID;
77

88
import io.a2a.client.http.A2ACardResolver;
9-
import io.a2a.client.http.A2AHttpClient;
10-
import io.a2a.client.http.JdkA2AHttpClient;
9+
import io.a2a.client.http.HttpClient;
1110
import io.a2a.spec.A2AClientError;
1211
import io.a2a.spec.A2AClientJSONError;
1312
import io.a2a.spec.AgentCard;
@@ -139,7 +138,7 @@ private static Message toMessage(List<Part<?>> parts, Message.Role role, String
139138
* @throws A2AClientJSONError f the response body cannot be decoded as JSON or validated against the AgentCard schema
140139
*/
141140
public static AgentCard getAgentCard(String agentUrl) throws A2AClientError, A2AClientJSONError {
142-
return getAgentCard(new JdkA2AHttpClient(), agentUrl);
141+
return getAgentCard(HttpClient.createHttpClient(agentUrl), agentUrl);
143142
}
144143

145144
/**
@@ -151,7 +150,7 @@ public static AgentCard getAgentCard(String agentUrl) throws A2AClientError, A2A
151150
* @throws A2AClientError If an HTTP error occurs fetching the card
152151
* @throws A2AClientJSONError f the response body cannot be decoded as JSON or validated against the AgentCard schema
153152
*/
154-
public static AgentCard getAgentCard(A2AHttpClient httpClient, String agentUrl) throws A2AClientError, A2AClientJSONError {
153+
public static AgentCard getAgentCard(HttpClient httpClient, String agentUrl) throws A2AClientError, A2AClientJSONError {
155154
return getAgentCard(httpClient, agentUrl, null, null);
156155
}
157156

@@ -167,7 +166,7 @@ public static AgentCard getAgentCard(A2AHttpClient httpClient, String agentUrl)
167166
* @throws A2AClientJSONError f the response body cannot be decoded as JSON or validated against the AgentCard schema
168167
*/
169168
public static AgentCard getAgentCard(String agentUrl, String relativeCardPath, Map<String, String> authHeaders) throws A2AClientError, A2AClientJSONError {
170-
return getAgentCard(new JdkA2AHttpClient(), agentUrl, relativeCardPath, authHeaders);
169+
return getAgentCard(HttpClient.createHttpClient(agentUrl), agentUrl, relativeCardPath, authHeaders);
171170
}
172171

173172
/**
@@ -182,7 +181,7 @@ public static AgentCard getAgentCard(String agentUrl, String relativeCardPath, M
182181
* @throws A2AClientError If an HTTP error occurs fetching the card
183182
* @throws A2AClientJSONError f the response body cannot be decoded as JSON or validated against the AgentCard schema
184183
*/
185-
public static AgentCard getAgentCard(A2AHttpClient httpClient, String agentUrl, String relativeCardPath, Map<String, String> authHeaders) throws A2AClientError, A2AClientJSONError {
184+
public static AgentCard getAgentCard(HttpClient httpClient, String agentUrl, String relativeCardPath, Map<String, String> authHeaders) throws A2AClientError, A2AClientJSONError {
186185
A2ACardResolver resolver = new A2ACardResolver(httpClient, agentUrl, relativeCardPath, authHeaders);
187186
return resolver.getAgentCard();
188187
}

client/base/src/test/java/io/a2a/client/ClientBuilderTest.java

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
package io.a2a.client;
22

33
import io.a2a.client.config.ClientConfig;
4-
import io.a2a.client.http.JdkA2AHttpClient;
4+
import io.a2a.client.http.HttpClientBuilder;
5+
import io.a2a.client.http.jdk.JdkHttpClientBuilder;
56
import io.a2a.client.transport.grpc.GrpcTransport;
67
import io.a2a.client.transport.grpc.GrpcTransportConfigBuilder;
78
import io.a2a.client.transport.jsonrpc.JSONRPCTransport;
@@ -71,13 +72,40 @@ public void shouldNotFindConfigurationTransport() throws A2AClientException {
7172
}
7273

7374
@Test
74-
public void shouldCreateJSONRPCClient() throws A2AClientException {
75+
public void shouldNotCreateJSONRPCClient_nullHttpClientFactory() throws A2AClientException {
76+
Assertions.assertThrows(IllegalArgumentException.class,
77+
() -> {
78+
Client
79+
.builder(card)
80+
.clientConfig(new ClientConfig.Builder().setUseClientPreference(true).build())
81+
.withTransport(JSONRPCTransport.class, new JSONRPCTransportConfigBuilder()
82+
.addInterceptor(null)
83+
.httpClientBuilder(null))
84+
.build();
85+
});
86+
}
87+
88+
@Test
89+
public void shouldCreateJSONRPCClient_defaultHttpClientFactory() throws A2AClientException {
90+
Client client = Client
91+
.builder(card)
92+
.clientConfig(new ClientConfig.Builder().setUseClientPreference(true).build())
93+
.withTransport(JSONRPCTransport.class, new JSONRPCTransportConfigBuilder()
94+
.addInterceptor(null)
95+
.httpClientBuilder(HttpClientBuilder.DEFAULT_FACTORY))
96+
.build();
97+
98+
Assertions.assertNotNull(client);
99+
}
100+
101+
@Test
102+
public void shouldCreateJSONRPCClient_withHttpClientFactory() throws A2AClientException {
75103
Client client = Client
76104
.builder(card)
77105
.clientConfig(new ClientConfig.Builder().setUseClientPreference(true).build())
78106
.withTransport(JSONRPCTransport.class, new JSONRPCTransportConfigBuilder()
79107
.addInterceptor(null)
80-
.httpClient(null))
108+
.httpClientBuilder(new JdkHttpClientBuilder()))
81109
.build();
82110

83111
Assertions.assertNotNull(client);
@@ -88,7 +116,7 @@ public void shouldCreateClient_differentConfigurations() throws A2AClientExcepti
88116
Client client = Client
89117
.builder(card)
90118
.withTransport(JSONRPCTransport.class, new JSONRPCTransportConfigBuilder())
91-
.withTransport(JSONRPCTransport.class, new JSONRPCTransportConfig(new JdkA2AHttpClient()))
119+
.withTransport(JSONRPCTransport.class, new JSONRPCTransportConfig())
92120
.build();
93121

94122
Assertions.assertNotNull(client);

client/transport/grpc/src/main/java/io/a2a/client/transport/grpc/GrpcTransport.java

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
import java.util.function.Consumer;
1212
import java.util.stream.Collectors;
1313

14+
import io.a2a.client.transport.spi.AbstractClientTransport;
1415
import io.a2a.client.transport.spi.interceptors.ClientCallContext;
15-
import io.a2a.client.transport.spi.ClientTransport;
1616
import io.a2a.client.transport.spi.interceptors.ClientCallInterceptor;
1717
import io.a2a.client.transport.spi.interceptors.PayloadAndHeaders;
1818
import io.a2a.client.transport.spi.interceptors.auth.AuthInterceptor;
@@ -50,7 +50,7 @@
5050
import io.grpc.stub.MetadataUtils;
5151
import io.grpc.stub.StreamObserver;
5252

53-
public class GrpcTransport implements ClientTransport {
53+
public class GrpcTransport extends AbstractClientTransport {
5454

5555
private static final Metadata.Key<String> AUTHORIZATION_METADATA_KEY = Metadata.Key.of(
5656
AuthInterceptor.AUTHORIZATION,
@@ -60,19 +60,18 @@ public class GrpcTransport implements ClientTransport {
6060
Metadata.ASCII_STRING_MARSHALLER);
6161
private final A2AServiceBlockingV2Stub blockingStub;
6262
private final A2AServiceStub asyncStub;
63-
private final List<ClientCallInterceptor> interceptors;
6463
private AgentCard agentCard;
6564

6665
public GrpcTransport(Channel channel, AgentCard agentCard) {
6766
this(channel, agentCard, null);
6867
}
6968

7069
public GrpcTransport(Channel channel, AgentCard agentCard, List<ClientCallInterceptor> interceptors) {
70+
super(interceptors);
7171
checkNotNullParam("channel", channel);
7272
this.asyncStub = A2AServiceGrpc.newStub(channel);
7373
this.blockingStub = A2AServiceGrpc.newBlockingV2Stub(channel);
7474
this.agentCard = agentCard;
75-
this.interceptors = interceptors;
7675
}
7776

7877
@Override
@@ -365,17 +364,4 @@ private String getTaskPushNotificationConfigName(String taskId, String pushNotif
365364
return name.toString();
366365
}
367366

368-
private PayloadAndHeaders applyInterceptors(String methodName, Object payload,
369-
AgentCard agentCard, ClientCallContext clientCallContext) {
370-
PayloadAndHeaders payloadAndHeaders = new PayloadAndHeaders(payload,
371-
clientCallContext != null ? clientCallContext.getHeaders() : null);
372-
if (interceptors != null && ! interceptors.isEmpty()) {
373-
for (ClientCallInterceptor interceptor : interceptors) {
374-
payloadAndHeaders = interceptor.intercept(methodName, payloadAndHeaders.getPayload(),
375-
payloadAndHeaders.getHeaders(), agentCard, clientCallContext);
376-
}
377-
}
378-
return payloadAndHeaders;
379-
}
380-
381367
}

0 commit comments

Comments
 (0)