From 8e573fe7cb8fa6bbcfe7f62c7f0ca838750dc9b1 Mon Sep 17 00:00:00 2001
From: ndr_brt <andrea.bertagnolli@gmail.com>
Date: Fri, 4 Aug 2023 14:08:58 +0200
Subject: [PATCH 1/2] docs: provide a multi-tenancy sample

---
 samples/multi-tenancy/README.md               | 109 ++++++++++++++++++
 samples/multi-tenancy/build.gradle.kts        |  46 ++++++++
 samples/multi-tenancy/config/first.properties |   9 ++
 .../multi-tenancy/config/second.properties    |   9 ++
 samples/multi-tenancy/config/third.properties |   9 ++
 .../multitenancy/MultiTenantRuntime.java      | 100 ++++++++++++++++
 .../multitenancy/MultiTenantRuntimeTest.java  |  55 +++++++++
 .../src/test/resources/tenants.properties     |  10 ++
 samples/multi-tenancy/tenants.properties      |   3 +
 settings.gradle.kts                           |   2 +
 10 files changed, 352 insertions(+)
 create mode 100644 samples/multi-tenancy/README.md
 create mode 100644 samples/multi-tenancy/build.gradle.kts
 create mode 100644 samples/multi-tenancy/config/first.properties
 create mode 100644 samples/multi-tenancy/config/second.properties
 create mode 100644 samples/multi-tenancy/config/third.properties
 create mode 100644 samples/multi-tenancy/src/main/java/org/eclipse/tractusx/edc/samples/multitenancy/MultiTenantRuntime.java
 create mode 100644 samples/multi-tenancy/src/test/java/org/eclipse/tractusx/edc/samples/multitenancy/MultiTenantRuntimeTest.java
 create mode 100644 samples/multi-tenancy/src/test/resources/tenants.properties
 create mode 100644 samples/multi-tenancy/tenants.properties

diff --git a/samples/multi-tenancy/README.md b/samples/multi-tenancy/README.md
new file mode 100644
index 000000000..ecc0bf60c
--- /dev/null
+++ b/samples/multi-tenancy/README.md
@@ -0,0 +1,109 @@
+# Multi Tenancy
+
+This sample show how to create a custom runtime to run multiple EDC tenants in a single java process.
+
+## How it works
+In a Java Runtime, multiple "sub-runtimes" with dedicated classloader can be launched in parallel, giving object-level
+separation (an object instantiated by a sub-runtime cannot be accessed by another sub-runtime).
+
+## How to use
+The module provides an extension of the `BaseRuntime` class called `MultiTenantRuntime`.
+This class can be set in the `build.gradle.kts` as the main class:
+```kotlin
+application {
+    mainClass.set("org.eclipse.tractusx.edc.samples.multitenancy.MultiTenantRuntime")
+}
+```
+
+This runtime looks for a properties file which path can be specified with the `edc.tenants.path` property.
+
+In this file the tenants are defined through settings, e.g.:
+```properties
+edc.tenants.tenant1.edc.fs.config=/config/path
+edc.tenants.tenant2.edc.fs.config=/config/path
+edc.tenants.tenant3.edc.fs.config=/config/path
+```
+
+Using this file the EDC will run with 3 tenants: `tenant1`, `tenant2` and `tenant3`, every one with their respective
+configuration file.
+Everything that stays after the tenant name in the setting key will be loaded in the tenant runtime, so *theoretically*
+(but not recommended) you could define all the tenants configuration in the tenants properties file:
+```properties
+edc.tenants.tenant1.web.http.port=18181
+edc.tenants.tenant1.any.other.setting=value
+edc.tenants.tenant2.web.http.port=28181
+edc.tenants.tenant3.web.http.port=38181
+```
+
+## Sample
+
+Build:
+```shell
+./gradlew :samples:multi-tenancy:build
+```
+
+Run:
+```shell
+java -jar -Dedc.tenants.path=samples/multi-tenancy/tenants.properties samples/multi-tenancy/build/libs/multitenant.jar
+```
+
+Create a PolicyDefinition on `first` tenant:
+```shell
+curl -X POST http://localhost:18183/management/v2/policydefinitions \
+    --header 'Content-Type: application/json' \
+    --data '{
+                "@context": { "@vocab": "https://w3id.org/edc/v0.0.1/ns/" },
+                "policy": {
+                    "@context": "http://www.w3.org/ns/odrl.jsonld",
+                    "@type": "set",
+                    "permission": [],
+                    "prohibition": [],
+                    "obligation": []
+                  }
+                }
+                '
+```
+
+Get `first` tenant assets:
+```shell
+curl -X POST http://localhost:18183/management/v2/policydefinitions/request
+```
+Will get a list containing the PolicyDefinition we created:
+```json
+[
+  {
+    "@id": "f48f2e27-c385-4846-b8b8-112c08bfa424",
+    "@type": "edc:PolicyDefinition",
+    "edc:createdAt": 1691147860257,
+    "edc:policy": {
+      "@id": "898fa3d6-b488-4f5f-9a41-4fb4b9229813",
+      "@type": "odrl:Set",
+      "odrl:permission": [],
+      "odrl:prohibition": [],
+      "odrl:obligation": []
+    },
+    "@context": {
+      "dct": "https://purl.org/dc/terms/",
+      "tx": "https://w3id.org/tractusx/v0.0.1/ns/",
+      "edc": "https://w3id.org/edc/v0.0.1/ns/",
+      "dcat": "https://www.w3.org/ns/dcat/",
+      "odrl": "http://www.w3.org/ns/odrl/2/",
+      "dspace": "https://w3id.org/dspace/v0.8/"
+    }
+  }
+]
+```
+
+`second` and `third` tenants will have no assets:
+```shell
+curl -X POST http://localhost:28183/management/v2/policydefinitions/request
+```
+and
+```shell
+curl -X POST http://localhost:38183/management/v2/policydefinitions/request
+```
+
+will return
+```json
+[]
+```
diff --git a/samples/multi-tenancy/build.gradle.kts b/samples/multi-tenancy/build.gradle.kts
new file mode 100644
index 000000000..2303cf86d
--- /dev/null
+++ b/samples/multi-tenancy/build.gradle.kts
@@ -0,0 +1,46 @@
+/*
+ *  Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft (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:
+ *       Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation
+ *
+ */
+
+plugins {
+    `java-library`
+    id("application")
+    id("com.github.johnrengelman.shadow") version "8.1.1"
+}
+
+
+dependencies {
+    implementation(libs.edc.boot)
+    implementation(project(":edc-controlplane:edc-controlplane-base")) {
+        exclude("org.eclipse.tractusx.edc", "data-encryption")
+        exclude(module = "ssi-miw-credential-client")
+        exclude(module = "ssi-identity-core")
+        exclude(module = "auth-tokenbased")
+    }
+    implementation(libs.edc.iam.mock)
+    implementation(libs.edc.core.controlplane)
+}
+
+application {
+    mainClass.set("org.eclipse.tractusx.edc.samples.multitenancy.MultiTenantRuntime")
+}
+
+tasks.withType<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar> {
+    mergeServiceFiles()
+    archiveFileName.set("multitenant.jar")
+}
+
+// do not publish
+edcBuild {
+    publish.set(false)
+}
diff --git a/samples/multi-tenancy/config/first.properties b/samples/multi-tenancy/config/first.properties
new file mode 100644
index 000000000..4b7a2f36d
--- /dev/null
+++ b/samples/multi-tenancy/config/first.properties
@@ -0,0 +1,9 @@
+web.http.port=18181
+web.http.path=/
+web.http.protocol.port=18182
+web.http.protocol.path=/protocol
+web.http.management.port=18183
+web.http.management.path=/management
+web.http.control.port=18184
+web.http.control.path=/control
+edc.dsp.callback.address=http://localhost:18182
diff --git a/samples/multi-tenancy/config/second.properties b/samples/multi-tenancy/config/second.properties
new file mode 100644
index 000000000..7abd9f8b7
--- /dev/null
+++ b/samples/multi-tenancy/config/second.properties
@@ -0,0 +1,9 @@
+web.http.port=28181
+web.http.path=/
+web.http.protocol.port=28182
+web.http.protocol.path=/protocol
+web.http.management.port=28183
+web.http.management.path=/management
+web.http.control.port=28184
+web.http.control.path=/control
+edc.dsp.callback.address=http://localhost:28182
diff --git a/samples/multi-tenancy/config/third.properties b/samples/multi-tenancy/config/third.properties
new file mode 100644
index 000000000..1fdd8593b
--- /dev/null
+++ b/samples/multi-tenancy/config/third.properties
@@ -0,0 +1,9 @@
+web.http.port=38181
+web.http.path=/
+web.http.protocol.port=38182
+web.http.protocol.path=/protocol
+web.http.management.port=38183
+web.http.management.path=/management
+web.http.control.port=38184
+web.http.control.path=/control
+edc.dsp.callback.address=http://localhost:38182
diff --git a/samples/multi-tenancy/src/main/java/org/eclipse/tractusx/edc/samples/multitenancy/MultiTenantRuntime.java b/samples/multi-tenancy/src/main/java/org/eclipse/tractusx/edc/samples/multitenancy/MultiTenantRuntime.java
new file mode 100644
index 000000000..6008b401c
--- /dev/null
+++ b/samples/multi-tenancy/src/main/java/org/eclipse/tractusx/edc/samples/multitenancy/MultiTenantRuntime.java
@@ -0,0 +1,100 @@
+/*
+ *  Copyright (c) 2022 Bayerische Motoren Werke Aktiengesellschaft (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:
+ *       Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - Initial implementation
+ *
+ */
+
+package org.eclipse.tractusx.edc.samples.multitenancy;
+
+import org.eclipse.edc.boot.system.runtime.BaseRuntime;
+import org.eclipse.edc.spi.EdcException;
+import org.eclipse.edc.spi.monitor.Monitor;
+import org.eclipse.edc.spi.system.configuration.Config;
+import org.eclipse.edc.spi.system.configuration.ConfigFactory;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.Properties;
+
+import static java.lang.ClassLoader.getSystemClassLoader;
+
+public class MultiTenantRuntime extends BaseRuntime {
+
+    private final @NotNull Monitor monitor = createMonitor();
+
+    public static void main(String[] args) {
+        var runtime = new MultiTenantRuntime();
+        runtime.boot();
+    }
+
+    protected void boot() {
+        loadTenantsConfig().getConfig("edc.tenants").partition().forEach(this::bootTenant);
+    }
+
+    private void bootTenant(Config tenantConfig) {
+        var baseProperties = System.getProperties();
+        tenantConfig.getRelativeEntries().forEach(System::setProperty);
+        var classPathEntries = Arrays.stream(System.getProperty("java.class.path").split(File.pathSeparator))
+                .map(this::toUrl)
+                .toArray(URL[]::new);
+
+        try (var classLoader = URLClassLoader.newInstance(classPathEntries, getSystemClassLoader())) {
+            var runtimeThread = new Thread(() -> {
+                try {
+                    Thread.currentThread().setContextClassLoader(classLoader);
+                    super.boot();
+                } catch (Exception e) {
+                    throw new EdcException(e);
+                }
+            });
+
+            monitor.info("Starting tenant " + tenantConfig.currentNode());
+            runtimeThread.start();
+
+            runtimeThread.join(20_000);
+
+        } catch (InterruptedException | IOException e) {
+            throw new EdcException(e);
+        } finally {
+            System.setProperties(baseProperties);
+        }
+    }
+
+    @NotNull
+    private Config loadTenantsConfig() {
+        var tenantsPath = System.getProperty("edc.tenants.path");
+        if (tenantsPath == null) {
+            throw new EdcException("No edc.tenants.path mandatory property provided");
+        }
+        try (var is = Files.newInputStream(Path.of(tenantsPath))) {
+            var properties = new Properties();
+            properties.load(is);
+            return ConfigFactory.fromProperties(properties);
+        } catch (IOException e) {
+            throw new EdcException(e);
+        }
+    }
+
+    private URL toUrl(String entry) {
+        try {
+            return new File(entry).toURI().toURL();
+        } catch (MalformedURLException e) {
+            throw new RuntimeException(e);
+        }
+    }
+}
diff --git a/samples/multi-tenancy/src/test/java/org/eclipse/tractusx/edc/samples/multitenancy/MultiTenantRuntimeTest.java b/samples/multi-tenancy/src/test/java/org/eclipse/tractusx/edc/samples/multitenancy/MultiTenantRuntimeTest.java
new file mode 100644
index 000000000..991446ebc
--- /dev/null
+++ b/samples/multi-tenancy/src/test/java/org/eclipse/tractusx/edc/samples/multitenancy/MultiTenantRuntimeTest.java
@@ -0,0 +1,55 @@
+package org.eclipse.tractusx.edc.samples.multitenancy;
+
+import org.eclipse.edc.spi.EdcException;
+import org.eclipse.edc.spi.monitor.Monitor;
+import org.jetbrains.annotations.NotNull;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentMatcher;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+class MultiTenantRuntimeTest {
+
+    private final Monitor monitor = mock();
+    private final MultiTenantRuntime runtime =
+            new MultiTenantRuntime() {
+                @Override
+                protected @NotNull Monitor createMonitor() {
+                    return monitor;
+                }
+            };
+
+    @Test
+    void throwsExceptionIfNoTenantsPropertyProvided() {
+        assertThrows(EdcException.class, runtime::boot);
+        verify(monitor, never()).info(argThat(connectorIsReady()));
+    }
+
+    @Test
+    void throwsExceptionIfTenantsFileDoesNotExist() {
+        System.setProperty("edc.tenants.path", "unexistentfile");
+
+        assertThrows(EdcException.class, runtime::boot);
+        verify(monitor, never()).info(argThat(connectorIsReady()));
+    }
+
+    @Test
+    void threadForEveryTenant() {
+        System.setProperty("edc.tenants.path", "./src/test/resources/tenants.properties");
+
+        runtime.boot();
+
+        verify(monitor, times(2)).info(argThat(connectorIsReady()));
+    }
+
+    @NotNull
+    private ArgumentMatcher<String> connectorIsReady() {
+        return message -> message.endsWith(" ready");
+    }
+
+}
diff --git a/samples/multi-tenancy/src/test/resources/tenants.properties b/samples/multi-tenancy/src/test/resources/tenants.properties
new file mode 100644
index 000000000..0362cfa59
--- /dev/null
+++ b/samples/multi-tenancy/src/test/resources/tenants.properties
@@ -0,0 +1,10 @@
+edc.tenants.one.edc.any=any
+edc.tenants.one.web.http.port=18181
+edc.tenants.one.web.http.path=/api
+edc.tenants.one.web.http.protocol.port=18282
+edc.tenants.one.web.http.protocol.path=/protocol
+edc.tenants.two.edc.any=any
+edc.tenants.two.web.http.port=28181
+edc.tenants.two.web.http.path=/api
+edc.tenants.two.web.http.protocol.port=28282
+edc.tenants.two.web.http.protocol.path=/protocol
diff --git a/samples/multi-tenancy/tenants.properties b/samples/multi-tenancy/tenants.properties
new file mode 100644
index 000000000..1f1b15a5e
--- /dev/null
+++ b/samples/multi-tenancy/tenants.properties
@@ -0,0 +1,3 @@
+edc.tenants.first.edc.fs.config=samples/multi-tenancy/config/first.properties
+edc.tenants.second.edc.fs.config=samples/multi-tenancy/config/second.properties
+edc.tenants.third.edc.fs.config=samples/multi-tenancy/config/third.properties
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 291dd368d..303ff0fea 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -82,6 +82,8 @@ include(":edc-extensions:dataplane-proxy:edc-dataplane-proxy-provider-core")
 include(":edc-extensions:dataplane-proxy:edc-dataplane-proxy-provider-api")
 include(":edc-tests:edc-dataplane-proxy-e2e")
 
+include(":samples:multi-tenancy")
+
 
 // this is needed to have access to snapshot builds of plugins
 pluginManagement {

From 0520c96c5bef9ada150111025c62735fd636c28e Mon Sep 17 00:00:00 2001
From: ndr_brt <andrea.bertagnolli@gmail.com>
Date: Fri, 4 Aug 2023 14:46:55 +0200
Subject: [PATCH 2/2] fix ci

---
 DEPENDENCIES                                  |  1 +
 samples/multi-tenancy/README.md               | 19 +++++++++++++++++--
 .../multitenancy/MultiTenantRuntime.java      | 10 +++++++---
 .../multitenancy/MultiTenantRuntimeTest.java  | 14 ++++++++++++++
 4 files changed, 39 insertions(+), 5 deletions(-)

diff --git a/DEPENDENCIES b/DEPENDENCIES
index 62aad4a97..d85031105 100644
--- a/DEPENDENCIES
+++ b/DEPENDENCIES
@@ -273,6 +273,7 @@ maven/mavencentral/org.eclipse.edc/dsp-transfer-process/0.2.0, Apache-2.0, appro
 maven/mavencentral/org.eclipse.edc/dsp/0.2.0, Apache-2.0, approved, technology.edc
 maven/mavencentral/org.eclipse.edc/http-spi/0.2.0, Apache-2.0, approved, technology.edc
 maven/mavencentral/org.eclipse.edc/http/0.2.0, Apache-2.0, approved, technology.edc
+maven/mavencentral/org.eclipse.edc/iam-mock/0.2.0, Apache-2.0, approved, technology.edc
 maven/mavencentral/org.eclipse.edc/jersey-core/0.2.0, Apache-2.0, approved, technology.edc
 maven/mavencentral/org.eclipse.edc/jersey-micrometer/0.2.0, Apache-2.0, approved, technology.edc
 maven/mavencentral/org.eclipse.edc/jersey-providers/0.2.0, Apache-2.0, approved, technology.edc
diff --git a/samples/multi-tenancy/README.md b/samples/multi-tenancy/README.md
index ecc0bf60c..3cc7e0dd2 100644
--- a/samples/multi-tenancy/README.md
+++ b/samples/multi-tenancy/README.md
@@ -3,12 +3,15 @@
 This sample show how to create a custom runtime to run multiple EDC tenants in a single java process.
 
 ## How it works
+
 In a Java Runtime, multiple "sub-runtimes" with dedicated classloader can be launched in parallel, giving object-level
 separation (an object instantiated by a sub-runtime cannot be accessed by another sub-runtime).
 
 ## How to use
+
 The module provides an extension of the `BaseRuntime` class called `MultiTenantRuntime`.
 This class can be set in the `build.gradle.kts` as the main class:
+
 ```kotlin
 application {
     mainClass.set("org.eclipse.tractusx.edc.samples.multitenancy.MultiTenantRuntime")
@@ -18,6 +21,7 @@ application {
 This runtime looks for a properties file which path can be specified with the `edc.tenants.path` property.
 
 In this file the tenants are defined through settings, e.g.:
+
 ```properties
 edc.tenants.tenant1.edc.fs.config=/config/path
 edc.tenants.tenant2.edc.fs.config=/config/path
@@ -28,6 +32,7 @@ Using this file the EDC will run with 3 tenants: `tenant1`, `tenant2` and `tenan
 configuration file.
 Everything that stays after the tenant name in the setting key will be loaded in the tenant runtime, so *theoretically*
 (but not recommended) you could define all the tenants configuration in the tenants properties file:
+
 ```properties
 edc.tenants.tenant1.web.http.port=18181
 edc.tenants.tenant1.any.other.setting=value
@@ -38,16 +43,19 @@ edc.tenants.tenant3.web.http.port=38181
 ## Sample
 
 Build:
+
 ```shell
 ./gradlew :samples:multi-tenancy:build
 ```
 
 Run:
+
 ```shell
 java -jar -Dedc.tenants.path=samples/multi-tenancy/tenants.properties samples/multi-tenancy/build/libs/multitenant.jar
 ```
 
 Create a PolicyDefinition on `first` tenant:
+
 ```shell
 curl -X POST http://localhost:18183/management/v2/policydefinitions \
     --header 'Content-Type: application/json' \
@@ -64,11 +72,14 @@ curl -X POST http://localhost:18183/management/v2/policydefinitions \
                 '
 ```
 
-Get `first` tenant assets:
+Get `first` tenant policy definitions:
+
 ```shell
 curl -X POST http://localhost:18183/management/v2/policydefinitions/request
 ```
+
 Will get a list containing the PolicyDefinition we created:
+
 ```json
 [
   {
@@ -94,16 +105,20 @@ Will get a list containing the PolicyDefinition we created:
 ]
 ```
 
-`second` and `third` tenants will have no assets:
+`second` and `third` tenants will have no policy definitions:
+
 ```shell
 curl -X POST http://localhost:28183/management/v2/policydefinitions/request
 ```
+
 and
+
 ```shell
 curl -X POST http://localhost:38183/management/v2/policydefinitions/request
 ```
 
 will return
+
 ```json
 []
 ```
diff --git a/samples/multi-tenancy/src/main/java/org/eclipse/tractusx/edc/samples/multitenancy/MultiTenantRuntime.java b/samples/multi-tenancy/src/main/java/org/eclipse/tractusx/edc/samples/multitenancy/MultiTenantRuntime.java
index 6008b401c..b9ddbec27 100644
--- a/samples/multi-tenancy/src/main/java/org/eclipse/tractusx/edc/samples/multitenancy/MultiTenantRuntime.java
+++ b/samples/multi-tenancy/src/main/java/org/eclipse/tractusx/edc/samples/multitenancy/MultiTenantRuntime.java
@@ -53,8 +53,9 @@ private void bootTenant(Config tenantConfig) {
                 .map(this::toUrl)
                 .toArray(URL[]::new);
 
+        Thread runtimeThread = null;
         try (var classLoader = URLClassLoader.newInstance(classPathEntries, getSystemClassLoader())) {
-            var runtimeThread = new Thread(() -> {
+            runtimeThread = new Thread(() -> {
                 try {
                     Thread.currentThread().setContextClassLoader(classLoader);
                     super.boot();
@@ -68,7 +69,10 @@ private void bootTenant(Config tenantConfig) {
 
             runtimeThread.join(20_000);
 
-        } catch (InterruptedException | IOException e) {
+        } catch (InterruptedException e) {
+            runtimeThread.interrupt();
+            throw new EdcException(e);
+        } catch (IOException e) {
             throw new EdcException(e);
         } finally {
             System.setProperties(baseProperties);
@@ -94,7 +98,7 @@ private URL toUrl(String entry) {
         try {
             return new File(entry).toURI().toURL();
         } catch (MalformedURLException e) {
-            throw new RuntimeException(e);
+            throw new EdcException(e);
         }
     }
 }
diff --git a/samples/multi-tenancy/src/test/java/org/eclipse/tractusx/edc/samples/multitenancy/MultiTenantRuntimeTest.java b/samples/multi-tenancy/src/test/java/org/eclipse/tractusx/edc/samples/multitenancy/MultiTenantRuntimeTest.java
index 991446ebc..5cd49157e 100644
--- a/samples/multi-tenancy/src/test/java/org/eclipse/tractusx/edc/samples/multitenancy/MultiTenantRuntimeTest.java
+++ b/samples/multi-tenancy/src/test/java/org/eclipse/tractusx/edc/samples/multitenancy/MultiTenantRuntimeTest.java
@@ -1,3 +1,17 @@
+/*
+ *  Copyright (c) 2022 Bayerische Motoren Werke Aktiengesellschaft (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:
+ *       Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - Initial implementation
+ *
+ */
+
 package org.eclipse.tractusx.edc.samples.multitenancy;
 
 import org.eclipse.edc.spi.EdcException;