Skip to content

Commit

Permalink
feat: Add capability to register an embedded dataplane
Browse files Browse the repository at this point in the history
  • Loading branch information
Marco Primo authored and Marco Primo committed Feb 21, 2024
1 parent 34c3285 commit 05f5b59
Show file tree
Hide file tree
Showing 6 changed files with 270 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright (c) 2022 Microsoft Corporation
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
*
* Contributors:
* Microsoft Corporation - initial API and implementation
* Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - improvements
* Mercedes-Benz Tech Innovation GmbH - publish public api context into dedicated swagger hub page
*
*/


plugins {
`java-library`
}

dependencies {
api(project(":spi:data-plane:data-plane-spi"))
implementation(project(":core:common:util"))
implementation(project(":spi:data-plane-selector:data-plane-selector-spi"))
implementation(project(":core:data-plane:data-plane-util"))

testImplementation(project(":core:common:junit"))
testImplementation(project(":spi:data-plane:data-plane-spi"))



implementation(libs.jakarta.rsApi)


}



Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.eclipse.edc.connector.dataplane.embedded.autoregistration;

public class EmbeddedDataPlaneConfig {
public static final String CONFIG_PREFIX = "edc.embedded.dataplane";
public static final String URL_SUFFIX = "url";
public static final String DESTINATION_TYPES_SUFFIX = "destinationtypes";
public static final String SOURCE_TYPES_SUFFIX = "sourcetypes";
public static final String PROPERTIES_SUFFIX = "properties";
public static final String PUBLIC_API_URL_PROPERTY = "publicApiUrl";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/*
* Copyright (c) 2021 Microsoft Corporation
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
*
* Contributors:
* Microsoft Corporation - Initial implementation
*
*/
package org.eclipse.edc.connector.dataplane.embedded.autoregistration;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.eclipse.edc.connector.dataplane.selector.spi.DataPlaneSelectorService;
import org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance;
import org.eclipse.edc.connector.dataplane.spi.manager.DataPlaneManager;
import org.eclipse.edc.runtime.metamodel.annotation.Inject;
import org.eclipse.edc.spi.EdcException;
import org.eclipse.edc.spi.monitor.Monitor;
import org.eclipse.edc.spi.system.ServiceExtension;
import org.eclipse.edc.spi.system.ServiceExtensionContext;
import org.eclipse.edc.spi.system.configuration.Config;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import static java.util.Objects.nonNull;

public class EmbeddedDataPlaneRegistration implements ServiceExtension {

private static final String NAME = "Embedded DataPlane Auto Registration";
private static final String COMMA = ",";
private static final String LOG_MISSING_CONFIGURATION = NAME + ": Missing configuration for " + EmbeddedDataPlaneConfig.CONFIG_PREFIX + ".%s.%s";
private static final String LOG_SKIP_BC_MISSING_CONFIGURATION = NAME + ": Configuration issues. Skip registering of Data Plane Instance '%s'";
private static final String LOG_REGISTERED = NAME + ": Registered Data Plane Instance. (id=%s, url=%s, sourceTypes=%s, destinationTypes=%s, properties=<omitted>)";
private Monitor monitor;
@Inject
private DataPlaneSelectorService selectorService;
@Override
public String name() {
return NAME;
}

@Override
public void initialize(ServiceExtensionContext context) {
this.monitor = context.getMonitor();
final Config config = context.getConfig(EmbeddedDataPlaneConfig.CONFIG_PREFIX);
context.getService(DataPlaneManager.class);
configureDataPlaneInstance(config);
}

public DataPlaneInstance createDataPlane(final Config config){

DataPlaneInstance dataPlaneInstance = null;
final String id = config.currentNode();
final String url = config.getString(EmbeddedDataPlaneConfig.URL_SUFFIX, "");
final List<String> sourceTypes =
Arrays.stream(config.getString(EmbeddedDataPlaneConfig.SOURCE_TYPES_SUFFIX, "").split(COMMA))
.map(String::trim)
.filter(Predicate.not(String::isEmpty))
.distinct()
.collect(Collectors.toList());
final List<String> destinationTypes =
Arrays.stream(config.getString(EmbeddedDataPlaneConfig.DESTINATION_TYPES_SUFFIX, "").split(COMMA))
.map(String::trim)
.filter(Predicate.not(String::isEmpty))
.distinct()
.collect(Collectors.toList());
final String propertiesJson = config.getString(EmbeddedDataPlaneConfig.PROPERTIES_SUFFIX, "{}");

if (url.isEmpty()) {
monitor.warning(String.format(LOG_MISSING_CONFIGURATION, id, EmbeddedDataPlaneConfig.URL_SUFFIX));
}

if (sourceTypes.isEmpty()) {
monitor.warning(String.format(LOG_MISSING_CONFIGURATION, id, EmbeddedDataPlaneConfig.SOURCE_TYPES_SUFFIX));
}

if (destinationTypes.isEmpty()) {
monitor.warning(String.format(LOG_MISSING_CONFIGURATION, id, EmbeddedDataPlaneConfig.DESTINATION_TYPES_SUFFIX));
}

final Map<String, String> properties;
try {
ObjectMapper mapper = new ObjectMapper();
properties = mapper.readValue(propertiesJson, new TypeReference<Map<String, String>>() {
});
} catch (JsonProcessingException e) {
throw new EdcException(e);
}

final boolean missingPublicApiProperty = !properties.containsKey(EmbeddedDataPlaneConfig.PUBLIC_API_URL_PROPERTY);
if (missingPublicApiProperty) {
monitor.warning(String.format(LOG_MISSING_CONFIGURATION, id, EmbeddedDataPlaneConfig.PROPERTIES_SUFFIX) + "." + EmbeddedDataPlaneConfig.PUBLIC_API_URL_PROPERTY);
}

final boolean invalidConfiguration =
url.isEmpty() || sourceTypes.isEmpty() || destinationTypes.isEmpty();
if (invalidConfiguration || missingPublicApiProperty) {
monitor.warning(String.format(LOG_SKIP_BC_MISSING_CONFIGURATION, id));
return null;
}
final DataPlaneInstance.Builder builder =
DataPlaneInstance.Builder.newInstance().id(id).url(url);

sourceTypes.forEach(builder::allowedSourceType);
destinationTypes.forEach(builder::allowedDestType);
properties.forEach(builder::property);

dataPlaneInstance = builder.build();

monitor.debug(
String.format(
LOG_REGISTERED,
id,
url,
String.join(", ", sourceTypes),
String.join(", ", destinationTypes)));
return dataPlaneInstance;
}
private void configureDataPlaneInstance(final Config config) {
var dataPlaneInstance = createDataPlane(config);
if(nonNull(dataPlaneInstance)){
selectorService.addInstance(dataPlaneInstance);
}


}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
org.eclipse.edc.connector.dataplane.embedded.autoregistration.EmbeddedDataPlaneRegistration
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@


/*
* Copyright (c) 2024 Zub4t (BMW AG)
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
*
* Contributors:
* Zub4t (BMW AG) - initial API and implementation
*
*/

package org.eclipse.edc.connector.dataplane.embedded.autoregistration;


import org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance;
import org.eclipse.edc.connector.dataplane.spi.manager.DataPlaneManager;
import org.eclipse.edc.junit.extensions.DependencyInjectionExtension;
import org.eclipse.edc.spi.system.ServiceExtensionContext;
import org.eclipse.edc.spi.system.configuration.ConfigFactory;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.IntStream;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.mock;

@ExtendWith(DependencyInjectionExtension.class)
public class EmbeddedDataPlaneRegistrationTest {

@Test
void testName(EmbeddedDataPlaneRegistration extension) {
Assertions.assertNotNull(extension.name());
Assertions.assertEquals("Embedded DataPlane Auto Registration", extension.name());
}
@Test
void embeddedDataPlaneRegistration_shouldThrowEdcException(EmbeddedDataPlaneRegistration extension, ServiceExtensionContext context) {
assertThrows(org.eclipse.edc.spi.EdcException.class, () -> {
extension.initialize(context);
var dataPlaneInstance = extension.createDataPlane(ConfigFactory.fromMap(Collections.emptyMap()));

});
}
@Test
void embeddedDataPlaneRegistration_shouldNotAddDataPlane(EmbeddedDataPlaneRegistration extension, ServiceExtensionContext context) {
var dataPlaneManager = mock(DataPlaneManager.class);
context.registerService(DataPlaneManager.class,dataPlaneManager);
extension.initialize(context);
var dataPlaneInstance = extension.createDataPlane(ConfigFactory.fromMap(Collections.emptyMap()));
assertThat(dataPlaneInstance).isNull();
}
@Test
void embeddedDataPlaneRegistration_shouldAddDataPlane(EmbeddedDataPlaneRegistration extension, ServiceExtensionContext context) {
var dataPlaneManager = mock(DataPlaneManager.class);
context.registerService(DataPlaneManager.class,dataPlaneManager);

List<String> keys = List.of(
EmbeddedDataPlaneConfig.DESTINATION_TYPES_SUFFIX,
EmbeddedDataPlaneConfig.SOURCE_TYPES_SUFFIX,
EmbeddedDataPlaneConfig.URL_SUFFIX,
EmbeddedDataPlaneConfig.PROPERTIES_SUFFIX);

List<String> values = List.of("HttpProxy,HttpData","HttpData","http://localhost:19192/control/transfer","{\"publicApiUrl\": \"http://localhost:19291/public/\"}");
Map<String, String> map = IntStream.range(0, keys.size())
.boxed()
.collect(HashMap::new, (m, i) -> m.put(keys.get(i), values.get(i)), Map::putAll);

extension.initialize(context);
var dataPlaneInstance = extension.createDataPlane(ConfigFactory.fromMap(map));
assertThat(dataPlaneInstance).isInstanceOf(DataPlaneInstance.class);
}
}
1 change: 1 addition & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ include(":extensions:data-plane:data-plane-http-oauth2-core")
include(":extensions:data-plane:data-plane-integration-tests")
include(":extensions:data-plane:store:sql:data-plane-store-sql")
include(":extensions:data-plane:data-plane-kafka")
include(":extensions:data-plane:embedded-data-plane-registration")

include(":extensions:data-plane-selector:data-plane-selector-api")
include(":extensions:data-plane-selector:data-plane-selector-client")
Expand Down

0 comments on commit 05f5b59

Please sign in to comment.