Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package org.apache.ignite.migrationtools.config;

import java.nio.file.Path;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.commons.lang3.reflect.FieldUtils;
Expand All @@ -27,7 +28,7 @@
import org.apache.ignite3.configuration.RootKey;
import org.apache.ignite3.configuration.annotation.ConfigurationType;
import org.apache.ignite3.configuration.validation.Validator;
import org.apache.ignite3.internal.configuration.ConfigurationModules;
import org.apache.ignite3.internal.configuration.CompoundModule;
import org.apache.ignite3.internal.configuration.ConfigurationRegistry;
import org.apache.ignite3.internal.configuration.ConfigurationTreeGenerator;
import org.apache.ignite3.internal.configuration.storage.LocalFileConfigurationStorage;
Expand All @@ -53,32 +54,44 @@ public class Ignite3ConfigurationUtils {
* @param includeDefaults Include defaults.
*/
public static CombinedConfigRegistry loadCombinedRegistry(Path nodeCfgPath, Path clusterCfgPath, boolean includeDefaults) {
var locReg = loadNodeConfiguration(nodeCfgPath, includeDefaults);
var distReg = loadClusterConfiguration(clusterCfgPath, includeDefaults);
List<ConfigurationModule> allModules = CompoundModule.loadAllConfigurationModules(null);

var locReg = loadNodeConfiguration(nodeCfgPath, allModules, includeDefaults);
var distReg = loadClusterConfiguration(clusterCfgPath, allModules, includeDefaults);
return new CombinedConfigRegistry(locReg, distReg);
}

/**
* Loads a Configuration Registry with only Node modules.
*
* @param cfgPath Configuration path.
* @param allModules All modules.
* @param includeDefaults Include defaults.
*/
public static ConfigurationRegistry loadNodeConfiguration(Path cfgPath, boolean includeDefaults) {
return loadConfigurations(cfgPath, ConfigurationModules.create(null).local(), includeDefaults);
public static ConfigurationRegistry loadNodeConfiguration(
Path cfgPath,
List<ConfigurationModule> allModules,
boolean includeDefaults
) {
return loadConfigurations(cfgPath, CompoundModule.local(allModules), includeDefaults);
}

/**
* Loads a Configuration Registry with only Cluster modules.
*
* @param cfgPath Config path.
* @param allModules All modules.
* @param includeDefaults Include defaults.
*/
public static ConfigurationRegistry loadClusterConfiguration(Path cfgPath, boolean includeDefaults) {
public static ConfigurationRegistry loadClusterConfiguration(
Path cfgPath,
List<ConfigurationModule> allModules,
boolean includeDefaults
) {
// Hack so that it passes the validation
// TODO: https://issues.apache.org/jira/browse/IGNITE-28137 This is another hack that needs to be cleaned.
// We don't really need the ConfigurationRegistry.
var distributedModule = ConfigurationModules.create(null).distributed();
var distributedModule = CompoundModule.distributed(allModules);
for (RootKey<?, ?, ?> key : distributedModule.rootKeys()) {
try {
FieldUtils.writeDeclaredField(key, "storageType", ConfigurationType.LOCAL, true);
Expand Down
2 changes: 2 additions & 0 deletions modules/configuration/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,11 @@ dependencies {
implementation libs.jetbrains.annotations
implementation libs.typesafe.config

testAnnotationProcessor libs.auto.service
testAnnotationProcessor project(':ignite-configuration-annotation-processor')
testImplementation project(':ignite-core')
testImplementation testFixtures(project(':ignite-core'))
testImplementation libs.auto.service.annotations
testImplementation libs.junit.testkit

testFixturesAnnotationProcessor project(':ignite-configuration-annotation-processor')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,16 @@

import java.util.Collection;
import java.util.List;
import java.util.ServiceLoader;
import java.util.ServiceLoader.Provider;
import java.util.Set;
import java.util.function.Function;
import org.apache.ignite.configuration.ConfigurationModule;
import org.apache.ignite.configuration.RootKey;
import org.apache.ignite.configuration.SuperRootChange;
import org.apache.ignite.configuration.annotation.ConfigurationType;
import org.apache.ignite.configuration.validation.Validator;
import org.jetbrains.annotations.Nullable;

/**
* {@link ConfigurationModule} that merges a few {@code ConfigurationModule}s.
Expand All @@ -37,11 +40,65 @@ public class CompoundModule implements ConfigurationModule {
private final ConfigurationType type;
private final List<ConfigurationModule> modules;

public CompoundModule(ConfigurationType type, Collection<ConfigurationModule> modules) {
private CompoundModule(ConfigurationType type, Collection<ConfigurationModule> modules) {
this.type = type;
this.modules = List.copyOf(modules);
}

/**
* Creates a compound local {@link ConfigurationModule} from the given collection.
*
* @param modules All configuration modules to filter.
* @return A compound module containing only {@link ConfigurationType#LOCAL} modules.
*/
public static ConfigurationModule local(Collection<ConfigurationModule> modules) {
return ofType(ConfigurationType.LOCAL, modules);
}

/**
* Creates a compound distributed {@link ConfigurationModule} from the given collection.
*
* @param modules All configuration modules to filter.
* @return A compound module containing only {@link ConfigurationType#DISTRIBUTED} modules.
*/
public static ConfigurationModule distributed(Collection<ConfigurationModule> modules) {
return ofType(ConfigurationType.DISTRIBUTED, modules);
}

/**
* Creates a compound {@link ConfigurationModule} of the specified type from the given collection.
*
* @param type The configuration type to filter by.
* @param modules All configuration modules to filter.
* @return A compound module containing only modules of the given type.
*/
private static ConfigurationModule ofType(ConfigurationType type, Collection<ConfigurationModule> modules) {
List<ConfigurationModule> filtered = modules.stream()
.filter(module -> module.type() == type)
.collect(toUnmodifiableList());
return new CompoundModule(type, filtered);
}

/**
* Loads all {@link ConfigurationModule}s from the classpath using the provided class loader.
*
* @param classLoader The class loader to use, or {@code null} to use the default class loader.
* @return All configuration modules found on the classpath.
* @throws IllegalStateException If no configuration modules are found.
*/
public static List<ConfigurationModule> loadAllConfigurationModules(@Nullable ClassLoader classLoader) {
List<ConfigurationModule> modules = ServiceLoader.load(ConfigurationModule.class, classLoader).stream()
.map(Provider::get)
.collect(toUnmodifiableList());

if (modules.isEmpty()) {
throw new IllegalStateException("No configuration modules were loaded. "
+ "Please make sure that the classloader for loading services is correct.");
}

return modules;
}

/** {@inheritDoc} */
@Override
public ConfigurationType type() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
package org.apache.ignite.internal.configuration;

import static java.util.Collections.emptyList;
import static org.apache.ignite.configuration.annotation.ConfigurationType.DISTRIBUTED;
import static org.apache.ignite.configuration.annotation.ConfigurationType.LOCAL;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.hasItem;
Expand All @@ -29,7 +31,6 @@
import java.util.Set;
import org.apache.ignite.configuration.ConfigurationModule;
import org.apache.ignite.configuration.RootKey;
import org.apache.ignite.configuration.annotation.ConfigurationType;
import org.apache.ignite.configuration.validation.Validator;
import org.apache.ignite.internal.testframework.BaseIgniteAbstractTest;
import org.junit.jupiter.api.BeforeEach;
Expand All @@ -44,6 +45,10 @@ class CompoundModuleTest extends BaseIgniteAbstractTest {
private RootKey<?, ?, ?> rootKeyA;
@Mock
private RootKey<?, ?, ?> rootKeyB;
@Mock
private RootKey<?, ?, ?> rootKeyC;
@Mock
private RootKey<?, ?, ?> rootKeyD;

@Mock
private Validator<AnnotationA, ?> validatorA;
Expand All @@ -54,19 +59,26 @@ class CompoundModuleTest extends BaseIgniteAbstractTest {
private ConfigurationModule moduleA;
@Mock
private ConfigurationModule moduleB;
@Mock
private ConfigurationModule moduleC;
@Mock
private ConfigurationModule moduleD;

private ConfigurationModule compound;

@BeforeEach
void createCompoundModule() {
compound = new CompoundModule(ConfigurationType.LOCAL, List.of(moduleA, moduleB));
when(moduleA.type()).thenReturn(LOCAL);
when(moduleB.type()).thenReturn(LOCAL);

compound = CompoundModule.local(List.of(moduleA, moduleB));
}

@Test
void returnsTypePassedViaConstructor() {
var compound = new CompoundModule(ConfigurationType.LOCAL, emptyList());
void returnsTypePassedViaFactory() {
ConfigurationModule compound = CompoundModule.local(emptyList());

assertThat(compound.type(), is(ConfigurationType.LOCAL));
assertThat(compound.type(), is(LOCAL));
}

@Test
Expand Down Expand Up @@ -114,6 +126,47 @@ void returnsUnionOfPolymorphicSchemaExtensionsOfItsModules() {
assertThat(compound.polymorphicSchemaExtensions(), containsInAnyOrder(ExtensionA.class, ExtensionB.class));
}

@Test
void localFiltersOnlyLocalModules() {
when(moduleA.type()).thenReturn(LOCAL);
when(moduleB.type()).thenReturn(LOCAL);
when(moduleC.type()).thenReturn(DISTRIBUTED);
when(moduleD.type()).thenReturn(DISTRIBUTED);
when(moduleA.rootKeys()).thenReturn(Set.of(rootKeyA));
when(moduleB.rootKeys()).thenReturn(Set.of(rootKeyB));

ConfigurationModule local = CompoundModule.local(List.of(moduleA, moduleB, moduleC, moduleD));

assertThat(local.rootKeys(), containsInAnyOrder(rootKeyA, rootKeyB));
}

@Test
void distributedFiltersOnlyDistributedModules() {
when(moduleA.type()).thenReturn(LOCAL);
when(moduleB.type()).thenReturn(LOCAL);
when(moduleC.type()).thenReturn(DISTRIBUTED);
when(moduleD.type()).thenReturn(DISTRIBUTED);
when(moduleC.rootKeys()).thenReturn(Set.of(rootKeyC));
when(moduleD.rootKeys()).thenReturn(Set.of(rootKeyD));

ConfigurationModule distributed = CompoundModule.distributed(List.of(moduleA, moduleB, moduleC, moduleD));

assertThat(distributed.rootKeys(), containsInAnyOrder(rootKeyC, rootKeyD));
}

@Test
void localAndDistributedFilterByType() {
when(moduleA.type()).thenReturn(LOCAL);
when(moduleB.type()).thenReturn(DISTRIBUTED);
when(moduleA.schemaExtensions()).thenReturn(Set.of(ExtensionA.class));
when(moduleB.schemaExtensions()).thenReturn(Set.of(ExtensionB.class));

List<ConfigurationModule> allModules = List.of(moduleA, moduleB);

assertThat(CompoundModule.local(allModules).schemaExtensions(), containsInAnyOrder(ExtensionA.class));
assertThat(CompoundModule.distributed(allModules).schemaExtensions(), containsInAnyOrder(ExtensionB.class));
}

private @interface AnnotationA {
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

package org.apache.ignite.internal.configuration;

import com.google.auto.service.AutoService;
import java.util.Collection;
import java.util.List;
import org.apache.ignite.configuration.ConfigurationModule;
Expand All @@ -27,6 +28,7 @@
/**
* Test configuration module.
*/
@AutoService(ConfigurationModule.class)
public class TestConfigurationModule implements ConfigurationModule {
@Override
public ConfigurationType type() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,12 @@

import org.apache.ignite.configuration.validation.Endpoint;
import org.apache.ignite.configuration.validation.ValidationContext;
import org.apache.ignite.internal.configuration.testframework.ConfigurationExtension;
import org.apache.ignite.internal.testframework.BaseIgniteAbstractTest;
import org.jetbrains.annotations.Nullable;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

/** Tests for {@link Endpoint}. */
@ExtendWith(ConfigurationExtension.class)
class EndpointValidatorTest extends BaseIgniteAbstractTest {
private static final EndpointValidator VALIDATOR = new EndpointValidator();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import static java.lang.reflect.Modifier.isStatic;
import static java.util.concurrent.CompletableFuture.allOf;
import static java.util.concurrent.Executors.newSingleThreadExecutor;
import static org.apache.ignite.configuration.annotation.ConfigurationType.DISTRIBUTED;
import static org.apache.ignite.configuration.annotation.ConfigurationType.LOCAL;
import static org.apache.ignite.internal.configuration.notifications.ConfigurationNotifier.notifyListeners;
import static org.apache.ignite.internal.configuration.testframework.InjectConfiguration.MOCK_ROOT_NAME;
Expand All @@ -39,7 +38,6 @@
import java.util.Collection;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.ServiceLoader;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
Expand Down Expand Up @@ -104,23 +102,12 @@ public class ConfigurationExtension implements BeforeEachCallback, AfterEachCall
private static final ConfigurationModule DISTRIBUTED_MODULE;

static {
// Automatically find all @InternalConfiguration and @PolymorphicConfigInstance classes
// to avoid configuring extensions manually in every test.
ServiceLoader<ConfigurationModule> modules = ServiceLoader.load(ConfigurationModule.class);

List<ConfigurationModule> localModules = new ArrayList<>();
List<ConfigurationModule> distributedModules = new ArrayList<>();

modules.forEach(configurationModule -> {
if (configurationModule.type() == LOCAL) {
localModules.add(configurationModule);
} else {
distributedModules.add(configurationModule);
}
});
// Automatically loads all ConfigurationModules presented on the classpath,
// so there is no need in manually configuring @InternalConfiguration and @PolymorphicConfigInstance classes in every test.
List<ConfigurationModule> modules = CompoundModule.loadAllConfigurationModules(null);

LOCAL_MODULE = new CompoundModule(LOCAL, localModules);
DISTRIBUTED_MODULE = new CompoundModule(DISTRIBUTED, distributedModules);
LOCAL_MODULE = CompoundModule.local(modules);
DISTRIBUTED_MODULE = CompoundModule.distributed(modules);
}

@Override
Expand Down
Loading