Skip to content

Commit 3e19159

Browse files
authored
refactor: discovery response improvements (#5789)
* refactor: discovery response improvements * chore: update management-api version
1 parent 3e35a4e commit 3e19159

10 files changed

Lines changed: 90 additions & 30 deletions

File tree

core/common/lib/json-ld-lib/src/main/resources/document/management-context-v2.jsonld

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -591,8 +591,12 @@
591591
"version": {
592592
"@id": "edc:version"
593593
},
594-
"counterPartyPath": {
595-
"@id": "edc:counterPartyPath"
594+
"counterParty": {
595+
"@id": "edc:counterParty",
596+
"@context": {
597+
"path": "edc:path",
598+
"dataServiceEndpoint": "edc:dataServiceEndpoint"
599+
}
596600
},
597601
"binding": {
598602
"@id": "edc:binding"

core/control-plane/control-plane-core/src/main/java/org/eclipse/edc/connector/controlplane/discovery/DiscoveryServiceImpl.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,27 +70,32 @@ public ServiceResult<List<DiscoveryResponse>> discover(String participantContext
7070

7171
private ServiceResult<List<DiscoveryResponse>> resolveMatches(String participantContextId, DiscoveryRequest request, DiscoveryUrlResolver resolver) {
7272

73-
var versionsResult = resolver.resolve(request).compose(this::fetchProtocolVersions);
73+
var wellKnownUrlResult = resolver.resolve(request);
74+
if (wellKnownUrlResult.failed()) {
75+
return ServiceResult.badRequest(wellKnownUrlResult.getFailureDetail());
76+
}
77+
var wellKnownUrl = wellKnownUrlResult.getContent();
78+
var versionsResult = fetchProtocolVersions(wellKnownUrl);
7479
if (versionsResult.failed()) {
7580
return ServiceResult.badRequest(versionsResult.getFailureDetail());
7681
}
7782

7883
var localProfiles = participantProfileService.resolveAll(participantContextId);
7984
var matches = localProfiles.stream()
80-
.flatMap(profileMatcher(versionsResult.getContent()))
85+
.flatMap(profileMatcher(wellKnownUrl, versionsResult.getContent()))
8186
.toList();
8287

8388
return ServiceResult.success(matches);
8489
}
8590

86-
private Function<DataspaceProfileContext, Stream<? extends DiscoveryResponse>> profileMatcher(List<ProtocolVersion> versions) {
91+
private Function<DataspaceProfileContext, Stream<? extends DiscoveryResponse>> profileMatcher(String wellKnownUrl, List<ProtocolVersion> versions) {
8792
return profile -> versions.stream()
8893
.filter(v -> v.version().equals(profile.protocolVersion().version()) &&
8994
v.binding().equals(profile.protocolVersion().binding()))
9095
.map(v -> new DiscoveryResponse(
9196
profile.name(),
9297
v.version(),
93-
v.path(),
98+
new DiscoveryResponse.CounterParty(v.path(), wellKnownUrl),
9499
v.binding()));
95100
}
96101

core/control-plane/control-plane-core/src/test/java/org/eclipse/edc/connector/controlplane/discovery/DiscoveryServiceImplTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,13 +120,13 @@ void shouldReturnMatchesForOverlappingProfiles() {
120120
.anySatisfy(m -> {
121121
assertThat(m.profile()).isEqualTo("dsp-2025-1");
122122
assertThat(m.version()).isEqualTo("2025-1");
123-
assertThat(m.counterPartyPath()).isEqualTo("/remote-2025");
123+
assertThat(m.counterParty().path()).isEqualTo("/remote-2025");
124124
assertThat(m.binding()).isEqualTo("http");
125125
})
126126
.anySatisfy(m -> {
127127
assertThat(m.profile()).isEqualTo("dsp-2024-1");
128128
assertThat(m.version()).isEqualTo("2024-1");
129-
assertThat(m.counterPartyPath()).isEqualTo("/remote-2024");
129+
assertThat(m.counterParty().path()).isEqualTo("/remote-2024");
130130
});
131131
}
132132

@@ -148,7 +148,7 @@ void shouldFilterByBothVersionAndBinding() {
148148
assertThat(result.getContent()).singleElement().satisfies(m -> {
149149
assertThat(m.profile()).isEqualTo("dsp-2025-1");
150150
assertThat(m.binding()).isEqualTo("http");
151-
assertThat(m.counterPartyPath()).isEqualTo("/remote-http");
151+
assertThat(m.counterParty().path()).isEqualTo("/remote-http");
152152
});
153153
}
154154

core/control-plane/control-plane-transform/src/main/java/org/eclipse/edc/connector/controlplane/transform/edc/discovery/from/JsonObjectFromDiscoveryResponseTransformer.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,10 @@
2323
import org.jetbrains.annotations.Nullable;
2424

2525
import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.TYPE;
26+
import static org.eclipse.edc.protocol.spi.discovery.DiscoveryResponse.COUNTER_PARTY_DATASERVICE_ENDPOINT_IRI;
27+
import static org.eclipse.edc.protocol.spi.discovery.DiscoveryResponse.COUNTER_PARTY_PATH_IRI;
2628
import static org.eclipse.edc.protocol.spi.discovery.DiscoveryResponse.DISCOVERY_RESPONSE_BINDING_IRI;
27-
import static org.eclipse.edc.protocol.spi.discovery.DiscoveryResponse.DISCOVERY_RESPONSE_COUNTER_PARTY_PATH_IRI;
29+
import static org.eclipse.edc.protocol.spi.discovery.DiscoveryResponse.DISCOVERY_RESPONSE_COUNTER_PARTY_IRI;
2830
import static org.eclipse.edc.protocol.spi.discovery.DiscoveryResponse.DISCOVERY_RESPONSE_PROFILE_IRI;
2931
import static org.eclipse.edc.protocol.spi.discovery.DiscoveryResponse.DISCOVERY_RESPONSE_TYPE_IRI;
3032
import static org.eclipse.edc.protocol.spi.discovery.DiscoveryResponse.DISCOVERY_RESPONSE_VERSION_IRI;
@@ -40,11 +42,16 @@ public JsonObjectFromDiscoveryResponseTransformer(JsonBuilderFactory jsonFactory
4042

4143
@Override
4244
public @Nullable JsonObject transform(@NotNull DiscoveryResponse match, @NotNull TransformerContext context) {
45+
var counterParty = jsonFactory.createObjectBuilder()
46+
.add(COUNTER_PARTY_PATH_IRI, match.counterParty().path())
47+
.add(COUNTER_PARTY_DATASERVICE_ENDPOINT_IRI, match.counterParty().dataServiceEndpoint())
48+
.build();
49+
4350
return jsonFactory.createObjectBuilder()
4451
.add(TYPE, DISCOVERY_RESPONSE_TYPE_IRI)
4552
.add(DISCOVERY_RESPONSE_PROFILE_IRI, match.profile())
4653
.add(DISCOVERY_RESPONSE_VERSION_IRI, match.version())
47-
.add(DISCOVERY_RESPONSE_COUNTER_PARTY_PATH_IRI, match.counterPartyPath())
54+
.add(DISCOVERY_RESPONSE_COUNTER_PARTY_IRI, counterParty)
4855
.add(DISCOVERY_RESPONSE_BINDING_IRI, match.binding())
4956
.build();
5057
}

core/control-plane/control-plane-transform/src/test/java/org/eclipse/edc/connector/controlplane/transform/edc/discovery/from/JsonObjectFromDiscoveryResponseTransformerTest.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,10 @@
2424

2525
import static org.assertj.core.api.Assertions.assertThat;
2626
import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.TYPE;
27+
import static org.eclipse.edc.protocol.spi.discovery.DiscoveryResponse.COUNTER_PARTY_DATASERVICE_ENDPOINT_IRI;
28+
import static org.eclipse.edc.protocol.spi.discovery.DiscoveryResponse.COUNTER_PARTY_PATH_IRI;
2729
import static org.eclipse.edc.protocol.spi.discovery.DiscoveryResponse.DISCOVERY_RESPONSE_BINDING_IRI;
28-
import static org.eclipse.edc.protocol.spi.discovery.DiscoveryResponse.DISCOVERY_RESPONSE_COUNTER_PARTY_PATH_IRI;
30+
import static org.eclipse.edc.protocol.spi.discovery.DiscoveryResponse.DISCOVERY_RESPONSE_COUNTER_PARTY_IRI;
2931
import static org.eclipse.edc.protocol.spi.discovery.DiscoveryResponse.DISCOVERY_RESPONSE_PROFILE_IRI;
3032
import static org.eclipse.edc.protocol.spi.discovery.DiscoveryResponse.DISCOVERY_RESPONSE_TYPE_IRI;
3133
import static org.eclipse.edc.protocol.spi.discovery.DiscoveryResponse.DISCOVERY_RESPONSE_VERSION_IRI;
@@ -44,15 +46,20 @@ void types() {
4446

4547
@Test
4648
void transform() {
47-
var match = new DiscoveryResponse("profile-1", "version", "/remote", "http");
49+
var match = new DiscoveryResponse("profile-1", "version",
50+
new DiscoveryResponse.CounterParty("/remote", "http://remote/dataservice"), "http");
4851

4952
var result = transformer.transform(match, context);
5053

5154
assertThat(result).isNotNull();
5255
assertThat(result.getString(TYPE)).isEqualTo(DISCOVERY_RESPONSE_TYPE_IRI);
5356
assertThat(result.getString(DISCOVERY_RESPONSE_PROFILE_IRI)).isEqualTo("profile-1");
54-
assertThat(result.getString(DISCOVERY_RESPONSE_COUNTER_PARTY_PATH_IRI)).isEqualTo("/remote");
5557
assertThat(result.getString(DISCOVERY_RESPONSE_VERSION_IRI)).isEqualTo("version");
5658
assertThat(result.getString(DISCOVERY_RESPONSE_BINDING_IRI)).isEqualTo("http");
59+
60+
var counterParty = result.getJsonObject(DISCOVERY_RESPONSE_COUNTER_PARTY_IRI);
61+
assertThat(counterParty).isNotNull();
62+
assertThat(counterParty.getString(COUNTER_PARTY_PATH_IRI)).isEqualTo("/remote");
63+
assertThat(counterParty.getString(COUNTER_PARTY_DATASERVICE_ENDPOINT_IRI)).isEqualTo("http://remote/dataservice");
5764
}
5865
}

extensions/common/api/management-api-configuration/src/main/resources/management-api-version.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
{
1515
"version": "5.0.0-beta",
1616
"urlPath": "/v5beta",
17-
"lastUpdated": "2026-05-28T09:00:00Z",
17+
"lastUpdated": "2026-05-29T09:00:00Z",
1818
"maturity": "beta"
1919
}
2020
]

extensions/common/api/management-api-schema-validator/src/main/resources/schema/management/v4/discovery-response-schema.json

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,8 @@
2727
"type": "string",
2828
"description": "The DSP protocol version shared by the local profile and the counter party entry."
2929
},
30-
"counterPartyPath": {
31-
"type": "string",
32-
"description": "The path under the counter party's base URL where the matching DSP version is exposed, as returned in the well-known versions document."
30+
"counterParty": {
31+
"$ref": "#/definitions/CounterParty"
3332
},
3433
"binding": {
3534
"type": "string",
@@ -40,9 +39,26 @@
4039
"@type",
4140
"profile",
4241
"version",
43-
"counterPartyPath",
42+
"counterParty",
4443
"binding"
4544
]
45+
},
46+
"CounterParty": {
47+
"type": "object",
48+
"description": "Counter party coordinates for a matched protocol version.",
49+
"properties": {
50+
"path": {
51+
"type": "string",
52+
"description": "The path under the counter party's base URL where the matching DSP version is exposed, as returned in the well-known versions document."
53+
},
54+
"dataServiceEndpoint": {
55+
"type": "string",
56+
"description": "The counter party's data service endpoint URL."
57+
}
58+
},
59+
"required": [
60+
"path"
61+
]
4662
}
4763
}
4864
}

extensions/control-plane/api/management-api-v5/discovery-api-v5/src/test/java/org/eclipse/edc/connector/controlplane/api/management/discovery/v5/DiscoveryApiV5ControllerTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@ void setUp() {
6868
void shouldReturnDiscoveredProfiles() {
6969
var request = new DiscoveryRequest(null, "https://counter-party.example");
7070
when(transformerRegistry.transform(isA(JsonObject.class), eq(DiscoveryRequest.class))).thenReturn(Result.success(request));
71-
var match = new DiscoveryResponse("profile-1", "version", "/remote", "http");
71+
var match = new DiscoveryResponse("profile-1", "version",
72+
new DiscoveryResponse.CounterParty("/remote", "http://remote/dataservice"), "http");
7273
when(discoveryService.discover(eq(PARTICIPANT_CONTEXT_ID), eq(request))).thenReturn(ServiceResult.success(List.of(match)));
7374
when(transformerRegistry.transform(isA(DiscoveryResponse.class), eq(JsonObject.class)))
7475
.thenReturn(Result.success(Json.createObjectBuilder().add("profile", "profile-1").build()));

spi/common/protocol-spi/src/main/java/org/eclipse/edc/protocol/spi/discovery/DiscoveryResponse.java

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,17 @@
2222
* Result of a discovery request: a local dataspace profile that matches a protocol version
2323
* advertised by the counterparty in its {@code /.well-known/dspace-version} document.
2424
*
25-
* @param profile the local profile id (i.e. the value of
26-
* {@link DataspaceProfileContext#name()}).
27-
* @param counterPartyPath the path under the counterparty's base URL where the matching DSP
28-
* version is exposed (as returned in the well-known versions document).
29-
* @param binding the protocol binding for this match (copied from the counterparty
30-
* version entry).
25+
* @param profile the local profile id (i.e. the value of
26+
* {@link DataspaceProfileContext#name()}).
27+
* @param version the DSP protocol version shared by the local profile and the
28+
* counterparty entry.
29+
* @param counterParty the counterparty coordinates for this match, see {@link CounterParty}.
30+
* @param binding the protocol binding for this match (copied from the counterparty
31+
* version entry).
3132
*/
3233
public record DiscoveryResponse(String profile,
3334
String version,
34-
String counterPartyPath,
35+
CounterParty counterParty,
3536
String binding) {
3637

3738
public static final String DISCOVERY_RESPONSE_TYPE_TERM = "DiscoveryResponse";
@@ -43,9 +44,25 @@ public record DiscoveryResponse(String profile,
4344
public static final String DISCOVERY_RESPONSE_VERSION_TERM = "version";
4445
public static final String DISCOVERY_RESPONSE_VERSION_IRI = EDC_NAMESPACE + DISCOVERY_RESPONSE_VERSION_TERM;
4546

46-
public static final String DISCOVERY_RESPONSE_COUNTER_PARTY_PATH_TERM = "counterPartyPath";
47-
public static final String DISCOVERY_RESPONSE_COUNTER_PARTY_PATH_IRI = EDC_NAMESPACE + DISCOVERY_RESPONSE_COUNTER_PARTY_PATH_TERM;
47+
public static final String DISCOVERY_RESPONSE_COUNTER_PARTY_TERM = "counterParty";
48+
public static final String DISCOVERY_RESPONSE_COUNTER_PARTY_IRI = EDC_NAMESPACE + DISCOVERY_RESPONSE_COUNTER_PARTY_TERM;
4849

4950
public static final String DISCOVERY_RESPONSE_BINDING_TERM = "binding";
5051
public static final String DISCOVERY_RESPONSE_BINDING_IRI = EDC_NAMESPACE + DISCOVERY_RESPONSE_BINDING_TERM;
52+
53+
public static final String COUNTER_PARTY_PATH_TERM = "path";
54+
public static final String COUNTER_PARTY_PATH_IRI = EDC_NAMESPACE + COUNTER_PARTY_PATH_TERM;
55+
56+
public static final String COUNTER_PARTY_DATASERVICE_ENDPOINT_TERM = "dataServiceEndpoint";
57+
public static final String COUNTER_PARTY_DATASERVICE_ENDPOINT_IRI = EDC_NAMESPACE + COUNTER_PARTY_DATASERVICE_ENDPOINT_TERM;
58+
59+
/**
60+
* Counterparty coordinates for a matched protocol version.
61+
*
62+
* @param path the path under the counterparty's base URL where the matching DSP
63+
* version is exposed (as returned in the well-known versions document).
64+
* @param dataServiceEndpoint the counterparty's data service endpoint URL.
65+
*/
66+
public record CounterParty(String path, String dataServiceEndpoint) {
67+
}
5168
}

system-tests/management-api/management-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/managementapi/v5/DiscoveryApiV5EndToEndTest.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,11 @@ void discover(ManagementEndToEndV5TestContext context, ParticipantContextService
9191
assertThat(entry.asJsonObject().getString(TYPE)).isEqualTo("DiscoveryResponse");
9292
assertThat(entry.asJsonObject().getString("profile")).isEqualTo("dsp2025_1");
9393
assertThat(entry.asJsonObject().getString("version")).isEqualTo("2025-1");
94-
assertThat(entry.asJsonObject().getString("counterPartyPath")).isNotNull();
9594
assertThat(entry.asJsonObject().getString("binding")).isNotNull();
95+
var counterParty = entry.asJsonObject().getJsonObject("counterParty");
96+
assertThat(counterParty).isNotNull();
97+
assertThat(counterParty.getString("path")).isNotNull();
98+
assertThat(counterParty.getString("dataServiceEndpoint")).isNotNull();
9699
});
97100
}
98101

0 commit comments

Comments
 (0)