Skip to content

Commit 7cdd35f

Browse files
authored
feat: add basic implementation for registering additional authorization profiles (#44)
1 parent df5a90c commit 7cdd35f

13 files changed

Lines changed: 419 additions & 24 deletions

File tree

src/main/java/org/eclipse/dataplane/Dataplane.java

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
import org.eclipse.dataplane.domain.dataflow.DataFlowStatusResponseMessage;
2828
import org.eclipse.dataplane.domain.dataflow.DataFlowSuspendMessage;
2929
import org.eclipse.dataplane.domain.dataflow.DataFlowTerminateMessage;
30+
import org.eclipse.dataplane.domain.registration.Authorization;
31+
import org.eclipse.dataplane.domain.registration.AuthorizationType;
3032
import org.eclipse.dataplane.domain.registration.ControlPlaneRegistrationMessage;
3133
import org.eclipse.dataplane.domain.registration.DataPlaneRegistrationMessage;
3234
import org.eclipse.dataplane.logic.OnCompleted;
@@ -37,6 +39,7 @@
3739
import org.eclipse.dataplane.logic.OnTerminate;
3840
import org.eclipse.dataplane.port.DataPlaneRegistrationApiController;
3941
import org.eclipse.dataplane.port.DataPlaneSignalingApiController;
42+
import org.eclipse.dataplane.port.exception.AuthorizationNotSupported;
4043
import org.eclipse.dataplane.port.exception.DataFlowNotifyControlPlaneFailed;
4144
import org.eclipse.dataplane.port.exception.DataplaneNotRegistered;
4245
import org.eclipse.dataplane.port.store.ControlPlaneStore;
@@ -48,9 +51,12 @@
4851
import java.net.http.HttpClient;
4952
import java.net.http.HttpRequest;
5053
import java.net.http.HttpResponse;
54+
import java.util.HashMap;
5155
import java.util.HashSet;
56+
import java.util.Map;
5257
import java.util.Set;
5358
import java.util.UUID;
59+
import java.util.function.BiConsumer;
5460

5561
import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;
5662
import static java.util.Collections.emptyMap;
@@ -73,6 +79,7 @@ public class Dataplane {
7379
private OnCompleted onCompleted = dataFlow -> Result.failure(new UnsupportedOperationException("onCompleted is not implemented"));
7480

7581
private final HttpClient httpClient = HttpClient.newHttpClient();
82+
private final Map<String, AuthorizationType> authorizationTypes = new HashMap<>();
7683

7784
public static Builder newInstance() {
7885
return new Builder();
@@ -229,7 +236,7 @@ public Result<Void> notifyCompleted(String dataFlowId) {
229236
.compose(dataFlow -> {
230237
dataFlow.transitionToCompleted();
231238

232-
return notifyControlPlane("completed", dataFlow, emptyMap()); // TODO DataFlowCompletedMessage not defined
239+
return notifyControlPlane("completed", dataFlow, emptyMap());
233240
});
234241
}
235242

@@ -300,13 +307,22 @@ private Result<Void> notifyControlPlane(String action, DataFlow dataFlow, Object
300307
return toJson(message)
301308
.map(body -> {
302309
var endpoint = dataFlow.callbackEndpointFor(action);
303-
var request = HttpRequest.newBuilder()
310+
var requestBuilder = HttpRequest.newBuilder()
304311
.uri(URI.create(endpoint))
305312
.header("content-type", "application/json")
306-
.POST(HttpRequest.BodyPublishers.ofString(body))
307-
.build();
313+
.POST(HttpRequest.BodyPublishers.ofString(body));
314+
315+
var controlPlane = controlPlaneStore.findByEndpoint(dataFlow.getCallbackAddress());
316+
if (controlPlane.succeeded()) {
317+
var authorization = controlPlane.getContent().authorization();
318+
if (authorization != null) {
319+
var authorizationType = authorizationTypes.get(authorization.getType());
320+
var castAuthorization = objectMapper.convertValue(authorization, authorizationType.authorizationClass());
321+
authorizationType.authorizationFunction().accept(requestBuilder, castAuthorization);
322+
}
323+
}
308324

309-
return httpClient.send(request, HttpResponse.BodyHandlers.discarding());
325+
return httpClient.send(requestBuilder.build(), HttpResponse.BodyHandlers.discarding());
310326
})
311327
.compose(response -> {
312328
var successful = response.statusCode() >= 200 && response.statusCode() < 300;
@@ -331,9 +347,16 @@ public ControlPlaneStore controlPlaneStore() {
331347
}
332348

333349
public Result<Void> registerControlPlane(ControlPlaneRegistrationMessage message) {
350+
for (var auth : message.authorization()) {
351+
if (!authorizationTypes.containsKey(auth.getType())) {
352+
return Result.failure(new AuthorizationNotSupported(auth));
353+
}
354+
}
355+
334356
var controlPlane = ControlPlane.newInstance()
335357
.id(message.controlplaneId())
336358
.endpoint(message.endpoint())
359+
.authorization(message.authorization())
337360
.build();
338361

339362
return controlPlaneStore.save(controlPlane);
@@ -406,5 +429,10 @@ public Builder onTerminate(OnTerminate onTerminate) {
406429
dataplane.onTerminate = onTerminate;
407430
return this;
408431
}
432+
433+
public <T extends Authorization> Builder registerAuthorization(String type, Class<T> authorizationClass, BiConsumer<HttpRequest.Builder, T> authorizationFunction) {
434+
dataplane.authorizationTypes.put(type, new AuthorizationType<>(type, authorizationClass, authorizationFunction));
435+
return this;
436+
}
409437
}
410438
}

src/main/java/org/eclipse/dataplane/domain/controlplane/ControlPlane.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,19 @@
1414

1515
package org.eclipse.dataplane.domain.controlplane;
1616

17+
import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
18+
import org.eclipse.dataplane.domain.registration.Authorization;
19+
import org.eclipse.dataplane.domain.registration.RawAuthorization;
20+
21+
import java.util.ArrayList;
22+
import java.util.List;
1723
import java.util.Objects;
1824

1925
public class ControlPlane {
2026

2127
private String id;
2228
private String endpoint;
29+
private final List<RawAuthorization> authorizations = new ArrayList<>();
2330

2431
public String getId() {
2532
return id;
@@ -33,6 +40,15 @@ public static ControlPlane.Builder newInstance() {
3340
return new ControlPlane.Builder();
3441
}
3542

43+
public List<RawAuthorization> getAuthorizations() {
44+
return authorizations;
45+
}
46+
47+
public Authorization authorization() {
48+
return getAuthorizations().stream().findAny().orElse(null);
49+
}
50+
51+
@JsonPOJOBuilder
3652
public static class Builder {
3753
private final ControlPlane controlPlane = new ControlPlane();
3854

@@ -55,5 +71,10 @@ public Builder endpoint(String endpoint) {
5571
controlPlane.endpoint = endpoint;
5672
return this;
5773
}
74+
75+
public Builder authorization(List<RawAuthorization> authorizations) {
76+
controlPlane.authorizations.addAll(authorizations);
77+
return this;
78+
}
5879
}
5980
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
* Copyright (c) 2026 Think-it GmbH
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Apache License, Version 2.0 which is available at
6+
* https://www.apache.org/licenses/LICENSE-2.0
7+
*
8+
* SPDX-License-Identifier: Apache-2.0
9+
*
10+
* Contributors:
11+
* Think-it GmbH - initial API and implementation
12+
*
13+
*/
14+
15+
package org.eclipse.dataplane.domain.registration;
16+
17+
public interface Authorization {
18+
19+
String getType();
20+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright (c) 2026 Think-it GmbH
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Apache License, Version 2.0 which is available at
6+
* https://www.apache.org/licenses/LICENSE-2.0
7+
*
8+
* SPDX-License-Identifier: Apache-2.0
9+
*
10+
* Contributors:
11+
* Think-it GmbH - initial API and implementation
12+
*
13+
*/
14+
15+
package org.eclipse.dataplane.domain.registration;
16+
17+
import java.net.http.HttpRequest;
18+
import java.util.function.BiConsumer;
19+
20+
public record AuthorizationType<T extends Authorization>(
21+
String type,
22+
Class<T> authorizationClass,
23+
BiConsumer<HttpRequest.Builder, T> authorizationFunction // TODO: dedicated interface
24+
) {
25+
26+
}

src/main/java/org/eclipse/dataplane/domain/registration/ControlPlaneRegistrationMessage.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,16 @@
1414

1515
package org.eclipse.dataplane.domain.registration;
1616

17+
import java.util.List;
18+
19+
import static java.util.Collections.emptyList;
20+
1721
public record ControlPlaneRegistrationMessage(
1822
String controlplaneId,
19-
String endpoint
20-
// TODO: authorization
23+
String endpoint,
24+
List<RawAuthorization> authorization
2125
) {
26+
public ControlPlaneRegistrationMessage(String controlplaneId, String endpoint) {
27+
this(controlplaneId, endpoint, emptyList());
28+
}
2229
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright (c) 2026 Think-it GmbH
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Apache License, Version 2.0 which is available at
6+
* https://www.apache.org/licenses/LICENSE-2.0
7+
*
8+
* SPDX-License-Identifier: Apache-2.0
9+
*
10+
* Contributors:
11+
* Think-it GmbH - initial API and implementation
12+
*
13+
*/
14+
15+
package org.eclipse.dataplane.domain.registration;
16+
17+
import com.fasterxml.jackson.annotation.JsonAnyGetter;
18+
import com.fasterxml.jackson.annotation.JsonAnySetter;
19+
20+
import java.util.HashMap;
21+
import java.util.Map;
22+
23+
public class RawAuthorization implements Authorization {
24+
25+
private final Map<String, Object> attributes = new HashMap<>();
26+
27+
@Override
28+
public String getType() {
29+
return attributes.get("type").toString();
30+
}
31+
32+
@JsonAnyGetter
33+
public Map<String, Object> getAttributes() {
34+
return attributes;
35+
}
36+
37+
@JsonAnySetter
38+
public void setAttribute(String key, Object value) {
39+
attributes.put(key, value);
40+
}
41+
}

src/main/java/org/eclipse/dataplane/port/ExceptionMapper.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@
1414

1515
package org.eclipse.dataplane.port;
1616

17+
import jakarta.ws.rs.BadRequestException;
1718
import jakarta.ws.rs.NotFoundException;
1819
import jakarta.ws.rs.WebApplicationException;
20+
import org.eclipse.dataplane.port.exception.AuthorizationNotSupported;
1921
import org.eclipse.dataplane.port.exception.ResourceNotFoundException;
2022

2123
import java.util.function.Function;
@@ -26,6 +28,11 @@ public interface ExceptionMapper {
2628
if (exception instanceof ResourceNotFoundException notFound) {
2729
return new NotFoundException(notFound);
2830
}
31+
32+
if (exception instanceof AuthorizationNotSupported authorizationNotSupported) {
33+
return new BadRequestException(authorizationNotSupported);
34+
}
35+
2936
return new WebApplicationException("unexpected internal server error");
3037
};
3138

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
* Copyright (c) 2026 Think-it GmbH
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Apache License, Version 2.0 which is available at
6+
* https://www.apache.org/licenses/LICENSE-2.0
7+
*
8+
* SPDX-License-Identifier: Apache-2.0
9+
*
10+
* Contributors:
11+
* Think-it GmbH - initial API and implementation
12+
*
13+
*/
14+
15+
package org.eclipse.dataplane.port.exception;
16+
17+
import org.eclipse.dataplane.domain.registration.Authorization;
18+
19+
public class AuthorizationNotSupported extends Exception {
20+
21+
public AuthorizationNotSupported(Authorization authorization) {
22+
super("Authorization type " + authorization.getType() + " not supported");
23+
}
24+
25+
}

src/main/java/org/eclipse/dataplane/port/store/ControlPlaneStore.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,6 @@ public interface ControlPlaneStore {
2323
Result<ControlPlane> findById(String controlplaneId);
2424

2525
Result<Void> delete(String id);
26+
27+
Result<ControlPlane> findByEndpoint(String endpoint);
2628
}

src/main/java/org/eclipse/dataplane/port/store/InMemoryControlPlaneStore.java

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
import java.util.HashMap;
2424
import java.util.Map;
25+
import java.util.Objects;
2526

2627
public class InMemoryControlPlaneStore implements ControlPlaneStore {
2728

@@ -44,17 +45,12 @@ public Result<Void> save(ControlPlane controlPlane) {
4445

4546
@Override
4647
public Result<ControlPlane> findById(String controlplaneId) {
47-
var dataFlow = store.get(controlplaneId);
48-
if (dataFlow == null) {
48+
var json = store.get(controlplaneId);
49+
if (json == null) {
4950
return Result.failure(new ResourceNotFoundException("ControlPlane %s not found".formatted(controlplaneId)));
5051
}
5152

52-
try {
53-
var deserialized = objectMapper.readValue(dataFlow, ControlPlane.class);
54-
return Result.success(deserialized);
55-
} catch (JsonProcessingException e) {
56-
return Result.failure(e);
57-
}
53+
return deserialize(json);
5854
}
5955

6056
@Override
@@ -65,4 +61,21 @@ public Result<Void> delete(String id) {
6561
}
6662
return Result.success();
6763
}
64+
65+
@Override
66+
public Result<ControlPlane> findByEndpoint(String endpoint) {
67+
return store.values().stream().map(this::deserialize).filter(Result::succeeded)
68+
.map(Result::getContent).filter(it -> Objects.equals(endpoint, it.getEndpoint()))
69+
.findAny().map(Result::success)
70+
.orElseGet(() -> Result.failure(new ResourceNotFoundException("ControlPlane with endpoint %s not found".formatted(endpoint))));
71+
}
72+
73+
private Result<ControlPlane> deserialize(String json) {
74+
try {
75+
var deserialized = objectMapper.readValue(json, ControlPlane.class);
76+
return Result.success(deserialized);
77+
} catch (JsonProcessingException e) {
78+
return Result.failure(e);
79+
}
80+
}
6881
}

0 commit comments

Comments
 (0)