Skip to content

Commit b6fe2f1

Browse files
authored
feat: add profile field in DSP versions (#5825)
1 parent d11cbd7 commit b6fe2f1

5 files changed

Lines changed: 68 additions & 38 deletions

File tree

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

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,19 +20,19 @@
2020
import org.eclipse.edc.http.spi.EdcHttpClient;
2121
import org.eclipse.edc.protocol.spi.DataspaceProfileContext;
2222
import org.eclipse.edc.protocol.spi.ParticipantProfileService;
23-
import org.eclipse.edc.protocol.spi.ProtocolVersion;
24-
import org.eclipse.edc.protocol.spi.ProtocolVersions;
2523
import org.eclipse.edc.protocol.spi.discovery.DiscoveryRequest;
2624
import org.eclipse.edc.protocol.spi.discovery.DiscoveryResponse;
2725
import org.eclipse.edc.protocol.spi.discovery.DiscoveryService;
2826
import org.eclipse.edc.protocol.spi.discovery.DiscoveryUrlResolver;
2927
import org.eclipse.edc.spi.result.Result;
3028
import org.eclipse.edc.spi.result.ServiceResult;
29+
import org.jetbrains.annotations.NotNull;
3130

3231
import java.io.IOException;
3332
import java.util.ArrayList;
3433
import java.util.List;
35-
import java.util.function.Function;
34+
import java.util.Optional;
35+
import java.util.function.Predicate;
3636
import java.util.stream.Stream;
3737

3838
public class DiscoveryServiceImpl implements DiscoveryService {
@@ -82,23 +82,26 @@ private ServiceResult<List<DiscoveryResponse>> resolveMatches(String participant
8282

8383
var localProfiles = participantProfileService.resolveAll(participantContextId);
8484
var matches = localProfiles.stream()
85-
.flatMap(profileMatcher(wellKnownUrl, versionsResult.getContent()))
85+
.flatMap((profile) -> profileFilter(profile, wellKnownUrl, versionsResult.getContent()))
8686
.toList();
8787

8888
return ServiceResult.success(matches);
8989
}
9090

91-
private Function<DataspaceProfileContext, Stream<? extends DiscoveryResponse>> profileMatcher(String wellKnownUrl, List<ProtocolVersion> versions) {
92-
return profile -> versions.stream()
93-
.filter(v -> v.version().equals(profile.protocolVersion().version()) &&
94-
v.binding().equals(profile.protocolVersion().binding()))
91+
private Stream<DiscoveryResponse> profileFilter(DataspaceProfileContext profile, String wellKnownUrl, List<ProtocolVersion> versions) {
92+
return versions.stream().filter(getProtocolVersionPredicate(profile))
9593
.map(v -> new DiscoveryResponse(
9694
profile.name(),
9795
v.version(),
9896
new DiscoveryResponse.CounterParty(v.path(), wellKnownUrl),
9997
v.binding()));
10098
}
10199

100+
private @NotNull Predicate<ProtocolVersion> getProtocolVersionPredicate(DataspaceProfileContext profile) {
101+
return v -> v.version().equals(profile.protocolVersion().version()) &&
102+
v.binding().equals(profile.protocolVersion().binding()) &&
103+
Optional.ofNullable(v.profile).map(profile.name()::equals).orElse(true);
104+
}
102105

103106
private ServiceResult<List<ProtocolVersion>> fetchProtocolVersions(String url) {
104107
var request = new Request.Builder().url(url).get().build();
@@ -126,4 +129,13 @@ private Result<List<ProtocolVersion>> handleResponse(Response response, String u
126129
public void registerResolver(DiscoveryUrlResolver resolver) {
127130
resolvers.add(resolver);
128131
}
132+
133+
// Records for deserializing the well-known document with experimental profile field.
134+
private record ProtocolVersions(List<ProtocolVersion> protocolVersions) {
135+
136+
}
137+
138+
private record ProtocolVersion(String profile, String version, String path, String binding) {
139+
140+
}
129141
}

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

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,30 @@ void shouldReturnMatchesForOverlappingProfiles() {
130130
});
131131
}
132132

133+
@Test
134+
void shouldReturnFilteredMatchesWhenProfileIsPresent() {
135+
service.registerResolver(resolver(true, ServiceResult.success(COUNTER_PARTY_BASE)));
136+
when(participantProfileService.resolveAll(PARTICIPANT)).thenReturn(List.of(
137+
profile("dsp-2025-1-ext", new ProtocolVersion("2025-1", "/local-2025-ext", "http"))
138+
));
139+
stubHttpVersions("""
140+
{"protocolVersions":[
141+
{"version":"2025-1", "profile": "dsp-2025-1", "path":"/remote-2025","binding":"http"},
142+
{"version":"2025-1", "profile": "dsp-2025-1-ext", "path":"/remote-2025-ext","binding":"http"}
143+
]}""");
144+
145+
var result = service.discover(PARTICIPANT, new DiscoveryRequest(null, COUNTER_PARTY_BASE));
146+
147+
assertThat(result.succeeded()).isTrue();
148+
assertThat(result.getContent()).hasSize(1)
149+
.allSatisfy(m -> {
150+
assertThat(m.profile()).isEqualTo("dsp-2025-1-ext");
151+
assertThat(m.version()).isEqualTo("2025-1");
152+
assertThat(m.counterParty().path()).isEqualTo("/remote-2025-ext");
153+
assertThat(m.binding()).isEqualTo("http");
154+
});
155+
}
156+
133157
@Test
134158
void shouldFilterByBothVersionAndBinding() {
135159
service.registerResolver(resolver(true, ServiceResult.success(COUNTER_PARTY_BASE)));
@@ -151,7 +175,7 @@ void shouldFilterByBothVersionAndBinding() {
151175
assertThat(m.counterParty().path()).isEqualTo("/remote-http");
152176
});
153177
}
154-
178+
155179
@Test
156180
void shouldFailWhenResolverReturnsFailure() {
157181
service.registerResolver(resolver(true, ServiceResult.notFound("no DataService endpoint")));

data-protocols/dsp/dsp-virtual/dsp-metadata-http-api-virtual/src/main/java/org/eclipse/edc/protocol/dsp/metadata/http/api/DspVirtualMetadataApiController.java

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
package org.eclipse.edc.protocol.dsp.metadata.http.api;
1616

17+
import jakarta.json.Json;
1718
import jakarta.json.JsonObject;
1819
import jakarta.ws.rs.GET;
1920
import jakarta.ws.rs.Path;
@@ -24,13 +25,17 @@
2425
import org.eclipse.edc.participantcontext.spi.service.ParticipantContextService;
2526
import org.eclipse.edc.protocol.spi.DataspaceProfileContext;
2627
import org.eclipse.edc.protocol.spi.ParticipantProfileService;
27-
import org.eclipse.edc.protocol.spi.ProtocolVersions;
2828
import org.eclipse.edc.spi.EdcException;
2929
import org.eclipse.edc.transform.spi.TypeTransformerRegistry;
3030

3131
import java.util.List;
3232

33+
import static jakarta.json.stream.JsonCollectors.toJsonArray;
3334
import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON;
35+
import static org.eclipse.edc.protocol.dsp.spi.type.DspVersionPropertyAndTypeNames.DSPACE_PROPERTY_BINDING;
36+
import static org.eclipse.edc.protocol.dsp.spi.type.DspVersionPropertyAndTypeNames.DSPACE_PROPERTY_PATH;
37+
import static org.eclipse.edc.protocol.dsp.spi.type.DspVersionPropertyAndTypeNames.DSPACE_PROPERTY_PROTOCOL_VERSIONS;
38+
import static org.eclipse.edc.protocol.dsp.spi.type.DspVersionPropertyAndTypeNames.DSPACE_PROPERTY_VERSION;
3439

3540
@Produces(APPLICATION_JSON)
3641
@Path("/{participantContextId}/.well-known/dspace-version")
@@ -57,33 +62,19 @@ public Response getProtocolVersions(@PathParam("participantContextId") String pa
5762
// Advertise only the DSP versions of profiles this participant is associated with.
5863
// A participant with no associated profiles returns an empty version list.
5964
var versions = profileResolver.resolveAll(participantContextId).stream()
60-
.map(DataspaceProfileContext::protocolVersion)
65+
.map(this::mapToProtocolVersion)
6166
.distinct()
62-
.toList();
67+
.collect(toJsonArray());
6368

64-
var protocolVersions = new ProtocolVersions(versions);
65-
var body = transformerRegistry.transform(protocolVersions, JsonObject.class);
66-
67-
if (body.failed()) {
68-
return internalServerError(body.getFailureMessages());
69-
}
7069
return Response.status(Response.Status.OK)
71-
.entity(body.getContent())
70+
.entity(Json.createObjectBuilder().add(DSPACE_PROPERTY_PROTOCOL_VERSIONS, versions).build())
7271
.build();
7372
}
74-
75-
private Response badRequest(List<String> messages) {
76-
return errorResponse(Response.Status.BAD_REQUEST, messages);
77-
}
78-
73+
7974
private Response notFound() {
8075
return errorResponse(Response.Status.NOT_FOUND, List.of());
8176
}
8277

83-
private Response internalServerError(List<String> messages) {
84-
return errorResponse(Response.Status.INTERNAL_SERVER_ERROR, messages);
85-
}
86-
8778
private Response errorResponse(Response.Status status, List<String> messages) {
8879
var error = VersionsError.Builder.newInstance().code(status.toString()).messages(messages).build();
8980
var body = transformerRegistry.transform(error, JsonObject.class)
@@ -94,4 +85,14 @@ private Response errorResponse(Response.Status status, List<String> messages) {
9485
.build();
9586
}
9687

88+
private JsonObject mapToProtocolVersion(DataspaceProfileContext context) {
89+
var protocolVersion = context.protocolVersion();
90+
return Json.createObjectBuilder()
91+
.add(DSPACE_PROPERTY_VERSION, protocolVersion.version())
92+
.add(DSPACE_PROPERTY_PATH, protocolVersion.path())
93+
.add(DSPACE_PROPERTY_BINDING, protocolVersion.binding())
94+
.add("profile", context.name())
95+
.build();
96+
}
97+
9798
}

data-protocols/dsp/dsp-virtual/dsp-metadata-http-api-virtual/src/test/java/org/eclipse/edc/protocol/dsp/metadata/http/api/DspVirtualMetadataApiControllerTest.java

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@
3636
import static io.restassured.RestAssured.given;
3737
import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON;
3838
import static org.hamcrest.CoreMatchers.is;
39-
import static org.mockito.ArgumentMatchers.any;
4039
import static org.mockito.ArgumentMatchers.eq;
4140
import static org.mockito.ArgumentMatchers.isA;
4241
import static org.mockito.Mockito.mock;
@@ -57,29 +56,23 @@ void shouldInvokeRequestHandler() {
5756
.thenReturn(ServiceResult.success(ParticipantContext.Builder.newInstance().identity("identity")
5857
.participantContextId("participantcontextId").build()));
5958
var protocolVersion = new ProtocolVersion("version", "/1.0", "binding");
60-
var output = Json.createObjectBuilder()
61-
.add("protocolVersions", Json.createArrayBuilder()
62-
.add(Json.createObjectBuilder()
63-
.add("version", protocolVersion.version())
64-
.add("path", protocolVersion.path())
65-
.add("binding", protocolVersion.binding())).build()).build();
6659

6760
var profile = new DataspaceProfileContext("profileId", protocolVersion, mock(), mock(), new JsonLdNamespace("https://example.org/dspace/"), List.of("https://example.org/context.jsonld"));
6861

6962
when(profileResolver.resolveAll(participantContextId)).thenReturn(List.of(profile));
70-
when(transformerRegistry.transform(any(), eq(JsonObject.class))).thenReturn(Result.success(output));
71-
7263

7364
baseRequest()
7465
.get("participantcontextId/.well-known/dspace-version")
7566
.then()
7667
.log().ifError()
7768
.statusCode(200)
7869
.contentType(APPLICATION_JSON)
70+
.body("protocolVersions[0].profile", is("profileId"))
7971
.body("protocolVersions[0].version", is(protocolVersion.version()))
8072
.body("protocolVersions[0].path", is(protocolVersion.path()))
8173
.body("protocolVersions[0].binding", is(protocolVersion.binding()));
8274

75+
8376
}
8477

8578
@Test

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ void discover(ManagementEndToEndV5TestContext context, ParticipantContextService
8787
var discovery = fetchDiscovery(context, providerContextId, participantTokenJwt, consumerContextId);
8888

8989

90-
assertThat(discovery).hasSize(2).allSatisfy(entry -> {
90+
assertThat(discovery).hasSize(1).allSatisfy(entry -> {
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");

0 commit comments

Comments
 (0)