Skip to content

Commit 2538fbf

Browse files
authored
feat(ServiceExtensionContext): freeze the ServiceExtensionContext before the prepare phase (#2023)
1 parent 01f797b commit 2538fbf

File tree

5 files changed

+52
-8
lines changed

5 files changed

+52
-8
lines changed

core/common/boot/src/main/java/org/eclipse/dataspaceconnector/boot/system/DefaultServiceExtensionContext.java

+14-6
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ public class DefaultServiceExtensionContext implements ServiceExtensionContext {
3939

4040
private final Map<Class<?>, Object> services = new HashMap<>();
4141
private final List<ConfigurationExtension> configurationExtensions;
42+
private boolean isReadOnly = false;
4243
private String connectorId;
4344
private Config config;
4445

@@ -51,6 +52,16 @@ public DefaultServiceExtensionContext(TypeManager typeManager, Monitor monitor,
5152
registerService(Clock.class, Clock.systemUTC());
5253
}
5354

55+
@Override
56+
public Config getConfig(String path) {
57+
return config.getConfig(path);
58+
}
59+
60+
@Override
61+
public void freeze() {
62+
isReadOnly = true;
63+
}
64+
5465
@Override
5566
public String getConnectorId() {
5667
return connectorId;
@@ -80,6 +91,9 @@ public <T> T getService(Class<T> type, boolean isOptional) {
8091

8192
@Override
8293
public <T> void registerService(Class<T> type, T service) {
94+
if (isReadOnly) {
95+
throw new EdcException("Cannot register service " + type.getName() + ", the ServiceExtensionContext is in read-only mode.");
96+
}
8397
if (hasService(type)) {
8498
getMonitor().warning("A service of the type " + type.getCanonicalName() + " was already registered and has now been replaced with a " + service.getClass().getSimpleName() + " instance.");
8599
}
@@ -96,11 +110,6 @@ public void initialize() {
96110
connectorId = getSetting("edc.connector.name", "edc-" + UUID.randomUUID());
97111
}
98112

99-
@Override
100-
public Config getConfig(String path) {
101-
return config.getConfig(path);
102-
}
103-
104113
// this method exists so that getting env vars can be mocked during testing
105114
protected Map<String, String> getEnvironmentVariables() {
106115
return System.getenv();
@@ -118,5 +127,4 @@ private Config loadConfig() {
118127

119128
return config.merge(environmentConfig).merge(systemPropertyConfig);
120129
}
121-
122130
}

core/common/boot/src/main/java/org/eclipse/dataspaceconnector/boot/system/ExtensionLoader.java

+2
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ public static void bootServiceExtensions(List<InjectionContainer<ServiceExtensio
6666
.map(ExtensionLifecycleManager::provide)
6767
.collect(Collectors.toList());
6868

69+
context.freeze();
70+
6971
var preparedExtensions = lifeCycles.stream().map(ExtensionLifecycleManager::prepare).collect(Collectors.toList());
7072
preparedExtensions.forEach(ExtensionLifecycleManager::start);
7173
}

core/common/boot/src/test/java/org/eclipse/dataspaceconnector/boot/system/DefaultServiceExtensionContextTest.java

+15-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
package org.eclipse.dataspaceconnector.boot.system;
1717

18+
import org.eclipse.dataspaceconnector.spi.EdcException;
1819
import org.eclipse.dataspaceconnector.spi.monitor.Monitor;
1920
import org.eclipse.dataspaceconnector.spi.system.ConfigurationExtension;
2021
import org.eclipse.dataspaceconnector.spi.system.configuration.Config;
@@ -30,13 +31,14 @@
3031
import java.util.Map;
3132

3233
import static org.assertj.core.api.Assertions.assertThat;
34+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
3335
import static org.mockito.Mockito.mock;
3436
import static org.mockito.Mockito.when;
3537

3638
class DefaultServiceExtensionContextTest {
3739

38-
private DefaultServiceExtensionContext context;
3940
private final ConfigurationExtension configuration = mock(ConfigurationExtension.class);
41+
private DefaultServiceExtensionContext context;
4042

4143
@BeforeEach
4244
void setUp() {
@@ -167,4 +169,16 @@ void loadConfig_systemPropOverwritesEnvVar() {
167169
}
168170
}
169171

172+
@Test
173+
void registerService_throwsWhenFrozen() {
174+
when(configuration.getConfig()).thenReturn(ConfigFactory.empty());
175+
context.initialize();
176+
177+
context.freeze();
178+
assertThatThrownBy(() -> context.registerService(Object.class, new Object() {
179+
})).isInstanceOf(EdcException.class).hasMessageStartingWith("Cannot register service");
180+
181+
182+
}
183+
170184
}

extensions/common/junit/src/test/java/org/eclipse/dataspaceconnector/junit/extensions/EdcExtensionTest.java

+13-1
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,16 @@
1515
package org.eclipse.dataspaceconnector.junit.extensions;
1616

1717
import okhttp3.OkHttpClient;
18+
import org.eclipse.dataspaceconnector.junit.testfixtures.MockVault;
19+
import org.eclipse.dataspaceconnector.spi.EdcException;
20+
import org.eclipse.dataspaceconnector.spi.security.Vault;
1821
import org.eclipse.dataspaceconnector.spi.system.MonitorExtension;
1922
import org.junit.jupiter.api.BeforeEach;
2023
import org.junit.jupiter.api.Test;
2124
import org.junit.jupiter.api.extension.ExtendWith;
2225

2326
import static org.assertj.core.api.Assertions.assertThat;
27+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
2428
import static org.mockito.ArgumentMatchers.startsWith;
2529
import static org.mockito.Mockito.atLeastOnce;
2630
import static org.mockito.Mockito.mock;
@@ -31,6 +35,7 @@ class EdcExtensionTest {
3135

3236
private OkHttpClient testClient;
3337

38+
3439
@BeforeEach
3540
void setUp(EdcExtension extension) {
3641
testClient = mock(OkHttpClient.class);
@@ -46,4 +51,11 @@ void registerServiceMock_serviceAlreadyExists(EdcExtension extension) {
4651
assertThat(extension.getContext().getService(OkHttpClient.class)).isEqualTo(testClient);
4752
verify(mockedMonitor, atLeastOnce()).warning(startsWith("TestServiceExtensionContext: A service mock was registered for type okhttp3.OkHttpClient"));
4853
}
49-
}
54+
55+
@Test
56+
void registerServiceMock_serviceContextReadOnlyMode(EdcExtension extension) {
57+
assertThatThrownBy(() -> extension.getContext().registerService(Vault.class, new MockVault()))
58+
.isInstanceOf(EdcException.class)
59+
.hasMessageStartingWith("Cannot register service");
60+
}
61+
}

spi/common/core-spi/src/main/java/org/eclipse/dataspaceconnector/spi/system/ServiceExtensionContext.java

+8
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,14 @@
2626
*/
2727
public interface ServiceExtensionContext extends SettingResolver {
2828

29+
/**
30+
* Freeze the context. It should mark the ServiceExtensionContext as read-only, preventing the registration
31+
* of new services after the initialization phase
32+
*/
33+
default void freeze() {
34+
35+
}
36+
2937
/**
3038
* Fetches the unique ID of the connector. If the {@code dataspaceconnector.connector.name} config value has been set, that value is returned; otherwise a random
3139
* name is chosen.

0 commit comments

Comments
 (0)