diff --git a/README.md b/README.md index 0c5621ad7..5e4522479 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# th2 common library (Java) (3.41.0) +# th2 common library (Java) (4.0.0) ## Usage @@ -309,6 +309,12 @@ dependencies { ## Release notes +### 4.0.0 + ++ Dynamic structure of common + + Extracted common/cassandra to separate module + + Implemented api for dynamic loading of modules and configurations + ### 3.41.0 + Work was done to eliminate vulnerabilities in _common_ and _bom_ dependencies. diff --git a/build.gradle b/build.gradle index 5e7b53c10..fd3ebf6fc 100644 --- a/build.gradle +++ b/build.gradle @@ -21,6 +21,7 @@ plugins { id 'signing' id 'com.google.protobuf' version '0.8.8' apply false id 'org.jetbrains.kotlin.jvm' version "${kotlin_version}" + id "org.jetbrains.kotlin.kapt" version "${kotlin_version}" id "org.owasp.dependencycheck" version "7.2.0" } @@ -38,6 +39,7 @@ ext { repositories { mavenCentral() + mavenLocal() maven { name 'Sonatype_snapshots' url 'https://s01.oss.sonatype.org/content/repositories/snapshots/' @@ -46,7 +48,6 @@ repositories { name 'Sonatype_releases' url 'https://s01.oss.sonatype.org/content/repositories/releases/' } - mavenLocal() configurations.all { resolutionStrategy.cacheChangingModulesFor 0, 'seconds' @@ -169,16 +170,22 @@ tasks.register('integrationTest', Test) { dependencies { api platform("com.exactpro.th2:bom:4.0.1") - api ("com.exactpro.th2:cradle-core:${cradleVersion}") { - exclude group: 'org.slf4j', module: 'slf4j-log4j12' // because of the vulnerability - } api 'com.exactpro.th2:grpc-common:3.11.1' implementation 'com.google.protobuf:protobuf-java-util' implementation 'com.exactpro.th2:grpc-service-generator:3.2.2' - implementation ("com.exactpro.th2:cradle-cassandra:${cradleVersion}") { - exclude group: 'org.slf4j', module: 'slf4j-log4j12' // because of the vulnerability - } + + // todo remove +// implementation 'com.exactpro.th2:full-cradle-manager:2.22.0-local' + implementation 'com.exactpro.th2:basic-cradle-manager:2.22.0-local' + implementation 'com.exactpro.th2:cradle-manager-api:2.22.0-local' + implementation "com.exactpro.th2:common-api-j:0.0.1" + + annotationProcessor 'com.google.auto.service:auto-service:1.0.1' + compileOnly 'com.google.auto.service:auto-service:1.0.1' + kapt 'com.google.auto.service:auto-service:1.0.1' + + implementation 'com.beust:jcommander:1.82' //FIXME: Add these dependencies as api to grpc-... artifacts implementation "io.grpc:grpc-protobuf" diff --git a/gradle.properties b/gradle.properties index 3abfd7183..128631790 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,7 +13,7 @@ # limitations under the License. # -release_version=3.41.0 +release_version=4.0.0 description = 'th2 common library (Java)' diff --git a/src/main/java/com/exactpro/th2/common/schema/factory/AbstractCommonFactory.java b/src/main/java/com/exactpro/th2/common/schema/factory/AbstractCommonFactory.java index ba074c6be..604196b70 100644 --- a/src/main/java/com/exactpro/th2/common/schema/factory/AbstractCommonFactory.java +++ b/src/main/java/com/exactpro/th2/common/schema/factory/AbstractCommonFactory.java @@ -16,10 +16,6 @@ package com.exactpro.th2.common.schema.factory; import com.exactpro.cradle.CradleManager; -import com.exactpro.cradle.cassandra.CassandraCradleManager; -import com.exactpro.cradle.cassandra.connection.CassandraConnection; -import com.exactpro.cradle.cassandra.connection.CassandraConnectionSettings; -import com.exactpro.cradle.utils.CradleStorageException; import com.exactpro.th2.common.event.Event; import com.exactpro.th2.common.grpc.EventBatch; import com.exactpro.th2.common.grpc.MessageBatch; @@ -30,9 +26,6 @@ import com.exactpro.th2.common.metrics.PrometheusConfiguration; import com.exactpro.th2.common.schema.box.configuration.BoxConfiguration; import com.exactpro.th2.common.schema.configuration.ConfigurationManager; -import com.exactpro.th2.common.schema.cradle.CradleConfidentialConfiguration; -import com.exactpro.th2.common.schema.cradle.CradleConfiguration; -import com.exactpro.th2.common.schema.cradle.CradleNonConfidentialConfiguration; import com.exactpro.th2.common.schema.dictionary.DictionaryType; import com.exactpro.th2.common.schema.event.EventBatchRouter; import com.exactpro.th2.common.schema.exception.CommonFactoryException; @@ -65,7 +58,6 @@ import com.fasterxml.jackson.module.kotlin.KotlinModule; import io.prometheus.client.exporter.HTTPServer; import io.prometheus.client.hotspot.DefaultExports; -import org.apache.commons.lang3.StringUtils; import org.apache.commons.text.StringSubstitutor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -95,8 +87,6 @@ import java.util.jar.Manifest; import java.util.stream.StreamSupport; -import static com.exactpro.cradle.cassandra.CassandraStorageSettings.DEFAULT_MAX_EVENT_BATCH_SIZE; -import static com.exactpro.cradle.cassandra.CassandraStorageSettings.DEFAULT_MAX_MESSAGE_BATCH_SIZE; import static java.util.Collections.emptyMap; import static java.util.Objects.requireNonNull; import static org.apache.commons.lang3.StringUtils.defaultIfBlank; @@ -109,7 +99,6 @@ */ public abstract class AbstractCommonFactory implements AutoCloseable { - protected static final String DEFAULT_CRADLE_INSTANCE_NAME = "infra"; protected static final String EXACTPRO_IMPLEMENTATION_VENDOR = "Exactpro Systems LLC"; /** @deprecated please use {@link #LOG4J_PROPERTIES_DEFAULT_PATH} */ @@ -384,23 +373,13 @@ public MessageRouter getCustomMessageRouter(Class messageClass) { return (MessageRouter)router; } - /** - * @return Configuration by specified path - * @throws IllegalStateException if can not read configuration - */ - public T getConfiguration(Path configPath, Class configClass, ObjectMapper customObjectMapper) { - return getConfigurationManager().loadConfiguration(customObjectMapper, stringSubstitutor, configClass, configPath, false); - } - - /** - * Load configuration, save and return. If already loaded return saved configuration. - * @param configClass configuration class - * @param optional creates an instance of a configuration class via the default constructor if this option is true and the config file doesn't exist or empty - * @return configuration object - */ - protected T getConfigurationOrLoad(Class configClass, boolean optional) { - return getConfigurationManager().getConfigurationOrLoad(MAPPER, stringSubstitutor, configClass, optional); - } +// /** +// * @return Configuration by specified path +// * @throws IllegalStateException if can not read configuration +// */ +// public T getConfiguration(Path configPath, Class configClass, ObjectMapper customObjectMapper) { +// return getConfigurationManager().loadConfiguration(customObjectMapper, stringSubstitutor, configClass, configPath, false); +// } public RabbitMQConfiguration getRabbitMqConfiguration() { return getConfigurationOrLoad(RabbitMQConfiguration.class, false); @@ -426,76 +405,22 @@ public BoxConfiguration getBoxConfiguration() { return getConfigurationOrLoad(BoxConfiguration.class, true); } - protected CradleConfidentialConfiguration getCradleConfidentialConfiguration() { - return getConfigurationOrLoad(CradleConfidentialConfiguration.class, false); - } - - protected CradleNonConfidentialConfiguration getCradleNonConfidentialConfiguration() { - return getConfigurationOrLoad(CradleNonConfidentialConfiguration.class, true); - } - /** - * @return Schema cradle configuration - * @throws IllegalStateException if cannot read configuration - * @deprecated please use {@link #getCradleManager()} + * @return Configuration by specified path + * @throws IllegalStateException if can not read configuration */ - @Deprecated - public CradleConfiguration getCradleConfiguration() { - return new CradleConfiguration(getCradleConfidentialConfiguration(), getCradleNonConfidentialConfiguration()); + public T getConfiguration(Path configPath, Class configClass, ObjectMapper customObjectMapper) { + return getConfigurationManager().loadConfiguration(customObjectMapper, stringSubstitutor, configClass, configPath, false); } /** - * @return Cradle manager - * @throws IllegalStateException if cannot read configuration or initialization failure + * Load configuration, save and return. If already loaded return saved configuration. + * @param configClass configuration class + * @param optional creates an instance of a configuration class via the default constructor if this option is true and the config file doesn't exist or empty + * @return configuration object */ - public CradleManager getCradleManager() { - return cradleManager.updateAndGet(manager -> { - if (manager == null) { - try { - CradleConfidentialConfiguration confidentialConfiguration = getCradleConfidentialConfiguration(); - CradleNonConfidentialConfiguration nonConfidentialConfiguration = getCradleNonConfidentialConfiguration(); - - CassandraConnectionSettings cassandraConnectionSettings = new CassandraConnectionSettings( - confidentialConfiguration.getDataCenter(), - confidentialConfiguration.getHost(), - confidentialConfiguration.getPort(), - confidentialConfiguration.getKeyspace()); - - if (StringUtils.isNotEmpty(confidentialConfiguration.getUsername())) { - cassandraConnectionSettings.setUsername(confidentialConfiguration.getUsername()); - } - - if (StringUtils.isNotEmpty(confidentialConfiguration.getPassword())) { - cassandraConnectionSettings.setPassword(confidentialConfiguration.getPassword()); - } - - if (nonConfidentialConfiguration.getTimeout() > 0) { - cassandraConnectionSettings.setTimeout(nonConfidentialConfiguration.getTimeout()); - } - - if (nonConfidentialConfiguration.getPageSize() > 0) { - cassandraConnectionSettings.setResultPageSize(nonConfidentialConfiguration.getPageSize()); - } - - manager = new CassandraCradleManager(new CassandraConnection(cassandraConnectionSettings)); - manager.init( - defaultIfBlank(confidentialConfiguration.getCradleInstanceName(), DEFAULT_CRADLE_INSTANCE_NAME), - nonConfidentialConfiguration.getPrepareStorage(), - nonConfidentialConfiguration.getCradleMaxMessageBatchSize() > 0 - ? nonConfidentialConfiguration.getCradleMaxMessageBatchSize() - : DEFAULT_MAX_MESSAGE_BATCH_SIZE, - nonConfidentialConfiguration.getCradleMaxEventBatchSize() > 0 - ? nonConfidentialConfiguration.getCradleMaxEventBatchSize() - : DEFAULT_MAX_EVENT_BATCH_SIZE - ); - } catch (CradleStorageException | RuntimeException e) { - throw new CommonFactoryException("Cannot create Cradle manager", e); - } - } - - return manager; - }); - + public T getConfigurationOrLoad(Class configClass, boolean optional) { + return getConfigurationManager().getConfigurationOrLoad(MAPPER, stringSubstitutor, configClass, optional); } /** diff --git a/src/main/java/com/exactpro/th2/common/schema/factory/CommonFactory.java b/src/main/java/com/exactpro/th2/common/schema/factory/CommonFactory.java index 399eb21f8..3dace61c7 100644 --- a/src/main/java/com/exactpro/th2/common/schema/factory/CommonFactory.java +++ b/src/main/java/com/exactpro/th2/common/schema/factory/CommonFactory.java @@ -15,15 +15,22 @@ package com.exactpro.th2.common.schema.factory; +import com.beust.jcommander.JCommander; +import com.exactpro.th2.common.ConfigurationProvider; +import com.exactpro.th2.common.ConfigurationProviderFactory; +import com.exactpro.th2.common.Module; +import com.exactpro.th2.common.ModuleApi; +import com.exactpro.th2.common.cli.CommonFactoryArgs; import com.exactpro.th2.common.grpc.EventBatch; import com.exactpro.th2.common.grpc.MessageBatch; import com.exactpro.th2.common.grpc.MessageGroupBatch; import com.exactpro.th2.common.grpc.RawMessageBatch; import com.exactpro.th2.common.metrics.PrometheusConfiguration; +import com.exactpro.th2.common.module.provider.FileConfigurationProvider; +import com.exactpro.th2.common.module.provider.FileConfigurationProviderConfig; import com.exactpro.th2.common.schema.box.configuration.BoxConfiguration; import com.exactpro.th2.common.schema.configuration.ConfigurationManager; -import com.exactpro.th2.common.schema.cradle.CradleConfidentialConfiguration; -import com.exactpro.th2.common.schema.cradle.CradleNonConfidentialConfiguration; +import com.exactpro.th2.common.schema.configuration.ConfigurationProviderConfig; import com.exactpro.th2.common.schema.dictionary.DictionaryType; import com.exactpro.th2.common.schema.event.EventBatchRouter; import com.exactpro.th2.common.schema.grpc.configuration.GrpcConfiguration; @@ -45,11 +52,6 @@ import io.fabric8.kubernetes.client.KubernetesClient; import io.fabric8.kubernetes.client.dsl.Resource; import kotlin.text.Charsets; -import org.apache.commons.cli.CommandLine; -import org.apache.commons.cli.DefaultParser; -import org.apache.commons.cli.Option; -import org.apache.commons.cli.Options; -import org.apache.commons.cli.ParseException; import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; @@ -63,6 +65,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.lang.reflect.InvocationTargetException; import java.nio.file.Files; import java.nio.file.Path; import java.util.Arrays; @@ -70,6 +73,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.ServiceLoader; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -83,7 +87,7 @@ /** * Default implementation for {@link AbstractCommonFactory} */ -public class CommonFactory extends AbstractCommonFactory { +public class CommonFactory extends AbstractCommonFactory implements ModuleApi { private static final Path CONFIG_DEFAULT_PATH = Path.of("/var/th2/config/"); @@ -91,12 +95,10 @@ public class CommonFactory extends AbstractCommonFactory { private static final String ROUTER_MQ_FILE_NAME = "mq.json"; private static final String GRPC_FILE_NAME = "grpc.json"; private static final String ROUTER_GRPC_FILE_NAME = "grpc_router.json"; - private static final String CRADLE_CONFIDENTIAL_FILE_NAME = "cradle.json"; private static final String PROMETHEUS_FILE_NAME = "prometheus.json"; private static final String CUSTOM_FILE_NAME = "custom.json"; private static final String BOX_FILE_NAME = "box.json"; private static final String CONNECTION_MANAGER_CONF_FILE_NAME = "mq_router.json"; - private static final String CRADLE_NON_CONFIDENTIAL_FILE_NAME = "cradle_manager.json"; /** @deprecated please use {@link #DICTIONARY_ALIAS_DIR_NAME} */ @Deprecated @@ -116,12 +118,19 @@ public class CommonFactory extends AbstractCommonFactory { private static final String CRADLE_EXTERNAL_MAP = "cradle-external"; private static final String LOGGING_CONFIG_MAP = "logging-config"; + private static final Class DEFAULT_CONFIGURATION_PROVIDER = FileConfigurationProvider.class; + private final Path custom; private final Path dictionaryTypesDir; private final Path dictionaryAliasesDir; private final Path oldDictionariesDir; private final ConfigurationManager configurationManager; + private static final ServiceLoader configurationProviderFactoryLoader + = ServiceLoader.load(ConfigurationProviderFactory.class); + + private final ConfigurationProvider configurationProvider; + private static final Logger LOGGER = LoggerFactory.getLogger(CommonFactory.class.getName()); protected CommonFactory(Class> messageRouterParsedBatchClass, @@ -134,7 +143,9 @@ protected CommonFactory(Class> messageRout @Nullable Path dictionaryAliasesDir, @Nullable Path oldDictionariesDir, Map environmentVariables, - ConfigurationManager configurationManager) { + ConfigurationManager configurationManager, + Class configurationProviderClass, + ConfigurationProviderConfig providerConfig) { super(messageRouterParsedBatchClass, messageRouterRawBatchClass, messageRouterMessageGroupBatchClass, eventBatchRouterClass, grpcRouterClass, environmentVariables); this.custom = defaultPathIfNull(custom, CUSTOM_FILE_NAME); @@ -143,6 +154,9 @@ protected CommonFactory(Class> messageRout this.oldDictionariesDir = requireNonNullElse(oldDictionariesDir, CONFIG_DEFAULT_PATH); this.configurationManager = configurationManager; + var factory = loadFactoryForProvider(configurationProviderClass); + this.configurationProvider = factory.get().create(providerConfig); + start(); } @@ -157,10 +171,11 @@ public CommonFactory(FactorySettings settings) { settings.getDictionaryAliasesDir(), settings.getOldDictionariesDir(), settings.getVariables(), - createConfigurationManager(settings)); + createConfigurationManager(settings), + settings.getConfigurationProviderClass(), + settings.getConfigurationProviderConfig()); } - /** * @deprecated Please use {@link CommonFactory#CommonFactory(FactorySettings)} */ @@ -177,6 +192,8 @@ public CommonFactory(Class> messageRouterP messageRouterMessageGroupBatchClass, eventBatchRouterClass, grpcRouterClass, + FileConfigurationProvider.class, + new FileConfigurationProviderConfig(), rabbitMQ, routerMQ, null, @@ -215,6 +232,10 @@ public CommonFactory() { this(new FactorySettings()); } + public ConfigurationProvider getConfigurationProvider() { + return configurationProvider; + } + @Override protected Path getPathToCustomConfiguration() { return custom; @@ -254,10 +275,6 @@ protected ConfigurationManager getConfigurationManager() { *

* --grpcRouterConfig - path to json file with configuration {@link GrpcRouterConfiguration} *

- * --cradleConfiguration - Deprecated!!! Please use cradleConfidentialConfiguration!!! Path to json file with configuration for cradle. ({@link CradleConfidentialConfiguration}) - *

- * --cradleConfidentialConfiguration - path to json file with configuration for cradle. ({@link CradleConfidentialConfiguration}) - *

* --customConfiguration - path to json file with custom configuration *

* --dictionariesDir - path to directory which contains files with encoded dictionaries @@ -268,14 +285,15 @@ protected ConfigurationManager getConfigurationManager() { *

* --connectionManagerConfiguration - path to json file with for {@link ConnectionManagerConfiguration} *

- * --cradleManagerConfiguration - path to json file with for {@link CradleNonConfidentialConfiguration} - *

* --namespace - namespace in Kubernetes to find config maps related to the target *

* --boxName - the name of the target th2 box placed in the specified namespace in Kubernetes *

* --contextName - context name to choose the context from Kube config *

+ * --configurationProviderClass - fully qualified class name of a {@link ConfigurationProvider} implementation that responsible for configuration reading. + * Also, each {@link ConfigurationProvider} may have its own parameters, refer to documentation of desirable implementation. + *

* --dictionaries - which dictionaries will be use, and types for it (example: fix-50=main fix-55=level1) * *

* -c/--configs - folder with json files for schemas configurations with special names: @@ -289,47 +307,21 @@ protected ConfigurationManager getConfigurationManager() { * @throws IllegalArgumentException - Cannot parse command line arguments */ public static CommonFactory createFromArguments(String... args) { - Options options = new Options(); - - Option configOption = new Option("c", "configs", true, null); - options.addOption(configOption); - - Option rabbitConfigurationOption = createLongOption(options, "rabbitConfiguration"); - Option messageRouterConfigurationOption = createLongOption(options, "messageRouterConfiguration"); - Option grpcRouterConfigurationOption = createLongOption(options, "grpcRouterConfiguration"); - Option grpcConfigurationOption = createLongOption(options, "grpcConfiguration"); - Option grpcRouterConfigOption = createLongOption(options, "grpcRouterConfig"); - Option cradleConfigurationOption = createLongOption(options, "cradleConfiguration"); - Option cradleConfidentialConfigurationOption = createLongOption(options, "cradleConfidentialConfiguration"); - Option customConfigurationOption = createLongOption(options, "customConfiguration"); - Option dictionariesDirOption = createLongOption(options, "dictionariesDir"); - Option prometheusConfigurationOption = createLongOption(options, "prometheusConfiguration"); - Option boxConfigurationOption = createLongOption(options, "boxConfiguration"); - Option namespaceOption = createLongOption(options, "namespace"); - Option boxNameOption = createLongOption(options, "boxName"); - Option contextNameOption = createLongOption(options, "contextName"); - Option dictionariesOption = createLongOption(options, "dictionaries"); - dictionariesOption.setArgs(Option.UNLIMITED_VALUES); - Option connectionManagerConfigurationOption = createLongOption(options, "connectionManagerConfiguration"); - Option cradleManagerConfigurationOption = createLongOption(options, "cradleManagerConfiguration"); try { - CommandLine cmd = new DefaultParser().parse(options, args); + CommonFactoryArgs parsedArgs = parseAsCommonConfig(args); - String configs = cmd.getOptionValue(configOption.getLongOpt()); + String configs = parsedArgs.config; - if (cmd.hasOption(namespaceOption.getLongOpt()) && cmd.hasOption(boxNameOption.getLongOpt())) { - String namespace = cmd.getOptionValue(namespaceOption.getLongOpt()); - String boxName = cmd.getOptionValue(boxNameOption.getLongOpt()); - String contextName = cmd.getOptionValue(contextNameOption.getLongOpt()); + if (parsedArgs.namespace != null && parsedArgs.boxName != null) { Map dictionaries = new HashMap<>(); - if (cmd.hasOption(dictionariesOption.getLongOpt())) { - for (String singleDictionary : cmd.getOptionValues(dictionariesOption.getLongOpt())) { + if (parsedArgs.dictionaries != null) { + for (String singleDictionary : parsedArgs.dictionaries) { String[] keyValue = singleDictionary.split("="); if (keyValue.length != 2 || StringUtils.isEmpty(keyValue[0].trim()) || StringUtils.isEmpty(keyValue[1].trim())) { - throw new IllegalStateException(String.format("Argument '%s' in '%s' option has wrong format.", singleDictionary, dictionariesOption.getLongOpt())); + throw new IllegalStateException(String.format("Argument '%s' in '%s' option has wrong format.", singleDictionary, "dictionaries")); } String typeStr = keyValue[1].trim(); @@ -344,34 +336,91 @@ public static CommonFactory createFromArguments(String... args) { } } - return createFromKubernetes(namespace, boxName, contextName, dictionaries); + return createFromKubernetes(parsedArgs.namespace, parsedArgs.boxName, parsedArgs.contextName, dictionaries); } if (configs != null) { configureLogger(configs); } FactorySettings settings = new FactorySettings(); - settings.setRabbitMQ(calculatePath(cmd, rabbitConfigurationOption, configs, RABBIT_MQ_FILE_NAME)); - settings.setRouterMQ(calculatePath(cmd, messageRouterConfigurationOption, configs, ROUTER_MQ_FILE_NAME)); - settings.setConnectionManagerSettings(calculatePath(cmd, connectionManagerConfigurationOption, configs, CONNECTION_MANAGER_CONF_FILE_NAME)); - settings.setGrpc(calculatePath(cmd, grpcConfigurationOption, grpcRouterConfigurationOption, configs, GRPC_FILE_NAME)); - settings.setRouterGRPC(calculatePath(cmd, grpcRouterConfigOption, configs, ROUTER_GRPC_FILE_NAME)); - settings.setCradleConfidential(calculatePath(cmd, cradleConfidentialConfigurationOption, cradleConfigurationOption, configs, CRADLE_CONFIDENTIAL_FILE_NAME)); - settings.setCradleNonConfidential(calculatePath(cmd, cradleManagerConfigurationOption, configs, CRADLE_NON_CONFIDENTIAL_FILE_NAME)); - settings.setPrometheus(calculatePath(cmd, prometheusConfigurationOption, configs, PROMETHEUS_FILE_NAME)); - settings.setBoxConfiguration(calculatePath(cmd, boxConfigurationOption, configs, BOX_FILE_NAME)); - settings.setCustom(calculatePath(cmd, customConfigurationOption, configs, CUSTOM_FILE_NAME)); - settings.setDictionaryTypesDir(calculatePath(cmd, dictionariesDirOption, configs, DICTIONARY_TYPE_DIR_NAME)); - settings.setDictionaryAliasesDir(calculatePath(cmd, dictionariesDirOption, configs, DICTIONARY_ALIAS_DIR_NAME)); - String oldDictionariesDir = cmd.getOptionValue(dictionariesDirOption.getLongOpt()); + settings.setRabbitMQ(calculatePath(parsedArgs.rabbitConfiguration, configs, RABBIT_MQ_FILE_NAME)); + settings.setRouterMQ(calculatePath(parsedArgs.messageRouterConfiguration, configs, ROUTER_MQ_FILE_NAME)); + settings.setConnectionManagerSettings(calculatePath(parsedArgs.connectionManagerConfiguration, configs, CONNECTION_MANAGER_CONF_FILE_NAME)); + settings.setGrpc(calculatePath(parsedArgs.grpcConfiguration, parsedArgs.grpcRouterConfiguration, configs, GRPC_FILE_NAME)); + settings.setRouterGRPC(calculatePath(parsedArgs.grpcRouterConfig, configs, ROUTER_GRPC_FILE_NAME)); + settings.setPrometheus(calculatePath(parsedArgs.prometheusConfiguration, configs, PROMETHEUS_FILE_NAME)); + settings.setBoxConfiguration(calculatePath(parsedArgs.boxConfiguration, configs, BOX_FILE_NAME)); + settings.setCustom(calculatePath(parsedArgs.customConfiguration, configs, CUSTOM_FILE_NAME)); + settings.setDictionaryTypesDir(calculatePath(parsedArgs.dictionariesDir, configs, DICTIONARY_TYPE_DIR_NAME)); + settings.setDictionaryAliasesDir(calculatePath(parsedArgs.dictionariesDir, configs, DICTIONARY_ALIAS_DIR_NAME)); + String oldDictionariesDir = parsedArgs.dictionariesDir; settings.setOldDictionariesDir(oldDictionariesDir == null ? (configs == null ? CONFIG_DEFAULT_PATH : Path.of(configs)) : Path.of(oldDictionariesDir)); + String configurationProviderClassName = defaultIfNull(parsedArgs.configurationProviderClass, DEFAULT_CONFIGURATION_PROVIDER.getName()); + + var providerClass = (Class) Class.forName(configurationProviderClassName); + var factory = loadFactoryForProvider(providerClass); + ConfigurationProviderFactory configurationProviderFactory = factory.get(); + + + ConfigurationProviderConfig configurationProviderConfig = + parseAs(args, configurationProviderFactory.getConfigClass().getDeclaredConstructor().newInstance()); + + settings.setConfigurationProviderClass(providerClass); + settings.setConfigurationProviderConfig(configurationProviderConfig); + return new CommonFactory(settings); - } catch (ParseException e) { + } catch (ClassNotFoundException e) { + LOGGER.error("Failed to find configuration provider class: " + e.getMessage()); throw new IllegalArgumentException("Incorrect arguments " + Arrays.toString(args), e); + } catch (InvocationTargetException | InstantiationException | IllegalAccessException | NoSuchMethodException e) { + LOGGER.error("Failed to create and initialize a new instance of ConfigurationProviderConfig: " + e.getMessage()); + throw new RuntimeException(e); } } + private static ConfigurationProviderConfig parseAs(String[] args, ConfigurationProviderConfig config) { + JCommander.newBuilder() + .addObject(config) + .addObject(new CommonFactoryArgs()) + .acceptUnknownOptions(false) + .build() + .parse(args); + return config; + } + private static CommonFactoryArgs parseAsCommonConfig(String[] args) { + CommonFactoryArgs commonFactoryArgs = new CommonFactoryArgs(); + JCommander.newBuilder() + .addObject(commonFactoryArgs) + .acceptUnknownOptions(true) + .build() + .parse(args); + return commonFactoryArgs; + } + + @NotNull + private static ServiceLoader.Provider loadFactoryForProvider( + Class providerClass) { + + var optionalFactory = configurationProviderFactoryLoader.stream() + .filter(factory -> factory.get().getType().equals(providerClass)) + .findFirst(); + return optionalFactory.orElseThrow(() -> { + LOGGER.error("Cannot find provider {}", providerClass); + return new IllegalArgumentException("Cannot find provider " + providerClass); + }); + } + + @Override + public @NotNull M loadModule(@NotNull Class clazz) { + if (configurationProvider == null) { + LOGGER.error("Configuration provider hasn't been provided"); + throw new IllegalStateException("Configuration provider hasn't been provided"); + } + return configurationManager.getModuleWithConfigurationProvider(clazz, configurationProvider); + } + + /** * Create {@link CommonFactory} via configs map from Kubernetes * @@ -480,8 +529,6 @@ public static CommonFactory createFromKubernetes(String namespace, String boxNam settings.setConnectionManagerSettings(writeFile(configPath, CONNECTION_MANAGER_CONF_FILE_NAME, boxData)); settings.setGrpc(writeFile(configPath, GRPC_FILE_NAME, boxData)); settings.setRouterGRPC(writeFile(configPath, ROUTER_GRPC_FILE_NAME, boxData)); - settings.setCradleConfidential(writeFile(configPath, CRADLE_CONFIDENTIAL_FILE_NAME, cradleConfigData)); - settings.setCradleNonConfidential(writeFile(configPath, CRADLE_NON_CONFIDENTIAL_FILE_NAME, boxData)); settings.setPrometheus(writeFile(configPath, PROMETHEUS_FILE_NAME, boxData)); settings.setCustom(writeFile(configPath, CUSTOM_FILE_NAME, boxData)); @@ -688,8 +735,6 @@ private static ConfigurationManager createConfigurationManager(FactorySettings s paths.put(ConnectionManagerConfiguration.class, defaultPathIfNull(settings.getConnectionManagerSettings(), CONNECTION_MANAGER_CONF_FILE_NAME)); paths.put(GrpcConfiguration.class, defaultPathIfNull(settings.getGrpc(), GRPC_FILE_NAME)); paths.put(GrpcRouterConfiguration.class, defaultPathIfNull(settings.getRouterGRPC(), ROUTER_GRPC_FILE_NAME)); - paths.put(CradleConfidentialConfiguration.class, defaultPathIfNull(settings.getCradleConfidential(), CRADLE_CONFIDENTIAL_FILE_NAME)); - paths.put(CradleNonConfidentialConfiguration.class, defaultPathIfNull(settings.getCradleNonConfidential(), CRADLE_NON_CONFIDENTIAL_FILE_NAME)); paths.put(PrometheusConfiguration.class, defaultPathIfNull(settings.getPrometheus(), PROMETHEUS_FILE_NAME)); paths.put(BoxConfiguration.class, defaultPathIfNull(settings.getBoxConfiguration(), BOX_FILE_NAME)); return new ConfigurationManager(paths); @@ -712,21 +757,11 @@ private static void writeToJson(Path path, Object object) throws IOException { } } - private static Option createLongOption(Options options, String optionName) { - Option option = new Option(null, optionName, true, null); - options.addOption(option); - return option; - } - private static Path calculatePath(String path, String configsPath, String fileName) { return path != null ? Path.of(path) : (configsPath != null ? Path.of(configsPath, fileName) : CONFIG_DEFAULT_PATH.resolve(fileName)); } - private static Path calculatePath(CommandLine cmd, Option option, String configs, String fileName) { - return calculatePath(cmd.getOptionValue(option.getLongOpt()), configs, fileName); - } - - private static Path calculatePath(CommandLine cmd, Option current, Option deprecated, String configs, String fileName) { - return calculatePath(defaultIfNull(cmd.getOptionValue(current.getLongOpt()), cmd.getOptionValue(deprecated.getLongOpt())), configs, fileName); + private static Path calculatePath(String current, String deprecated, String configs, String fileName) { + return calculatePath(defaultIfNull(current, deprecated), configs, fileName); } } diff --git a/src/main/kotlin/com/exactpro/th2/common/cli/CommonFactoryArgs.kt b/src/main/kotlin/com/exactpro/th2/common/cli/CommonFactoryArgs.kt new file mode 100644 index 000000000..56da830ea --- /dev/null +++ b/src/main/kotlin/com/exactpro/th2/common/cli/CommonFactoryArgs.kt @@ -0,0 +1,71 @@ +/* + * Copyright 2020-2022 Exactpro (Exactpro Systems Limited) + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.exactpro.th2.common.cli + +import com.beust.jcommander.Parameter + + +class CommonFactoryArgs { + + @Parameter(names = ["-c", "--configs"]) + lateinit var config: String + + @Parameter(names = ["--rabbitConfiguration"]) + lateinit var rabbitConfiguration: String + + @Parameter(names = ["--messageRouterConfiguration"]) + lateinit var messageRouterConfiguration: String + + @Parameter(names = ["--grpcRouterConfiguration"]) + lateinit var grpcRouterConfiguration: String + + @Parameter(names = ["--grpcConfiguration"]) + lateinit var grpcConfiguration: String + + @Parameter(names = ["--grpcRouterConfig"]) + lateinit var grpcRouterConfig: String + + @Parameter(names = ["--customConfiguration"]) + lateinit var customConfiguration: String + + @Parameter(names = ["--dictionariesDir"]) + lateinit var dictionariesDir: String + + @Parameter(names = ["--prometheusConfiguration"]) + lateinit var prometheusConfiguration: String + + @Parameter(names = ["--boxConfiguration"]) + lateinit var boxConfiguration: String + + @Parameter(names = ["--namespace"]) + lateinit var namespace: String + + @Parameter(names = ["--boxName"]) + lateinit var boxName: String + + @Parameter(names = ["--contextName"]) + lateinit var contextName: String + + @Parameter(names = ["--dictionaries"]) + lateinit var dictionaries: List + + @Parameter(names = ["--connectionManagerConfiguration"]) + lateinit var connectionManagerConfiguration: String + + @Parameter(names = ["--configurationProviderClass"]) + lateinit var configurationProviderClass: String + +} \ No newline at end of file diff --git a/src/main/kotlin/com/exactpro/th2/common/module/provider/FileConfigurationProvider.kt b/src/main/kotlin/com/exactpro/th2/common/module/provider/FileConfigurationProvider.kt new file mode 100644 index 000000000..fb492510a --- /dev/null +++ b/src/main/kotlin/com/exactpro/th2/common/module/provider/FileConfigurationProvider.kt @@ -0,0 +1,35 @@ +/* + * Copyright 2020-2022 Exactpro (Exactpro Systems Limited) + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.exactpro.th2.common.module.provider + +import com.exactpro.th2.common.ConfigurationProvider +import com.exactpro.th2.common.schema.configuration.Configuration +import com.fasterxml.jackson.databind.ObjectMapper +import java.nio.file.Paths + + +class FileConfigurationProvider( + private val objectMapper: ObjectMapper, + private val configurationDir: String, + private val fileExtension: String +) : ConfigurationProvider { + + + override fun loadConfiguration(configId: String, cfgClass: Class): C { + return objectMapper.readValue(Paths.get(configurationDir, "$configId.$fileExtension").toFile(), cfgClass) + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/exactpro/th2/common/module/provider/FileConfigurationProviderConfig.kt b/src/main/kotlin/com/exactpro/th2/common/module/provider/FileConfigurationProviderConfig.kt new file mode 100644 index 000000000..bfbd80eab --- /dev/null +++ b/src/main/kotlin/com/exactpro/th2/common/module/provider/FileConfigurationProviderConfig.kt @@ -0,0 +1,32 @@ +/* + * Copyright 2020-2022 Exactpro (Exactpro Systems Limited) + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.exactpro.th2.common.module.provider + +import com.beust.jcommander.Parameter +import com.exactpro.th2.common.schema.configuration.ConfigurationProviderConfig + +class FileConfigurationProviderConfig: ConfigurationProviderConfig { + @Parameter(names = ["--file-provider-path"], required = false) + var fileProviderPath: String = "/opt/th2/config" + + @Parameter(names = ["--file-provider-extension"], required = false) + var fileProviderExtension: String = "json" + + override fun toString(): String { + return "FileConfigurationProviderConfig(fileProviderPath='$fileProviderPath', fileProviderExtension='$fileProviderExtension')" + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/exactpro/th2/common/module/provider/FileConfigurationProviderFactory.kt b/src/main/kotlin/com/exactpro/th2/common/module/provider/FileConfigurationProviderFactory.kt new file mode 100644 index 000000000..5ca297a1d --- /dev/null +++ b/src/main/kotlin/com/exactpro/th2/common/module/provider/FileConfigurationProviderFactory.kt @@ -0,0 +1,59 @@ +/* + * Copyright 2020-2022 Exactpro (Exactpro Systems Limited) + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.exactpro.th2.common.module.provider + +import com.exactpro.th2.common.ConfigurationProvider +import com.exactpro.th2.common.ConfigurationProviderFactory +import com.exactpro.th2.common.schema.configuration.ConfigurationProviderConfig +import com.exactpro.th2.common.schema.strategy.route.json.RoutingStrategyModule +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule +import com.fasterxml.jackson.module.kotlin.registerKotlinModule +import com.google.auto.service.AutoService + +@AutoService(ConfigurationProviderFactory::class) +open class FileConfigurationProviderFactory : ConfigurationProviderFactory { + + private val objectMapper: ObjectMapper = ObjectMapper() + + init { + objectMapper.registerKotlinModule() + objectMapper.registerModules( + RoutingStrategyModule(objectMapper), + JavaTimeModule() + ) + } + + override val configClass: Class + get() = FileConfigurationProviderConfig::class.java + + override val type: Class + get() = FileConfigurationProvider::class.java + + + override fun create(config: ConfigurationProviderConfig): ConfigurationProvider { + if (config is FileConfigurationProviderConfig) { + return FileConfigurationProvider( + objectMapper, + config.fileProviderPath, + config.fileProviderExtension + ) + } else { + throw IllegalArgumentException("Wrong provider config: expected FileConfigurationProviderConfig, actual ${config::class.java}") + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/exactpro/th2/common/schema/configuration/Configuration.kt b/src/main/kotlin/com/exactpro/th2/common/schema/configuration/Configuration.kt deleted file mode 100644 index d2b06e52b..000000000 --- a/src/main/kotlin/com/exactpro/th2/common/schema/configuration/Configuration.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2020-2021 Exactpro (Exactpro Systems Limited) - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.exactpro.th2.common.schema.configuration - -import com.fasterxml.jackson.annotation.JsonAnySetter -import org.slf4j.Logger -import org.slf4j.LoggerFactory - -open class Configuration { - - protected val logger: Logger = LoggerFactory.getLogger(this::class.java) - - @JsonAnySetter - fun setField(name: String, value: Any?) { - logger.warn("Ignore unknown field with name '{}' in configuration class '{}'", name, this::class.java.name) - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/exactpro/th2/common/schema/configuration/ConfigurationManager.kt b/src/main/kotlin/com/exactpro/th2/common/schema/configuration/ConfigurationManager.kt index cebcad3db..4fe5f966e 100644 --- a/src/main/kotlin/com/exactpro/th2/common/schema/configuration/ConfigurationManager.kt +++ b/src/main/kotlin/com/exactpro/th2/common/schema/configuration/ConfigurationManager.kt @@ -1,5 +1,5 @@ /* - * Copyright 2020-2021 Exactpro (Exactpro Systems Limited) + * Copyright 2020-2022 Exactpro (Exactpro Systems Limited) * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -15,16 +15,28 @@ package com.exactpro.th2.common.schema.configuration +import com.exactpro.th2.common.ConfigurationProvider +import com.exactpro.th2.common.Module +import com.exactpro.th2.common.ModuleFactory import com.fasterxml.jackson.databind.ObjectMapper -import mu.KotlinLogging -import org.apache.commons.text.StringSubstitutor import java.io.IOException import java.nio.file.Files import java.nio.file.Path +import java.util.ServiceLoader import java.util.concurrent.ConcurrentHashMap +import mu.KotlinLogging +import org.apache.commons.text.StringSubstitutor class ConfigurationManager(private val configurationPath: Map, Path>) { - private val configurations: MutableMap, Any?> = ConcurrentHashMap() + private val configurationCache: MutableMap, Any?> = ConcurrentHashMap() + private val moduleCache: MutableMap, Module> = ConcurrentHashMap() + private val modulesFactoryMapping: MutableMap, ModuleFactory> = ConcurrentHashMap() + + init { + ServiceLoader.load(ModuleFactory::class.java).forEach { moduleFactory -> + modulesFactoryMapping[moduleFactory.moduleType] = moduleFactory + } + } fun loadConfiguration( objectMapper: ObjectMapper, @@ -48,13 +60,25 @@ class ConfigurationManager(private val configurationPath: Map, Path>) { } } + fun getModuleWithConfigurationProvider( + moduleClass: Class, + configurationProvider: ConfigurationProvider + ): T { + return moduleCache.computeIfAbsent(moduleClass) { + checkNotNull(modulesFactoryMapping[moduleClass]) { + LOGGER.error { "Mapping does not contain module factory for $moduleClass" } + "Mapping does not contain module factory for $moduleClass" + }.create(configurationProvider) + } as T + } + fun getConfigurationOrLoad( objectMapper: ObjectMapper, stringSubstitutor: StringSubstitutor, configClass: Class, optional: Boolean ): T { - return configurations.computeIfAbsent(configClass) { + return configurationCache.computeIfAbsent(configClass) { checkNotNull(configurationPath[configClass]) { "Unknown class $configClass" }.let { diff --git a/src/main/kotlin/com/exactpro/th2/common/schema/cradle/CradleConfiguration.kt b/src/main/kotlin/com/exactpro/th2/common/schema/cradle/CradleConfiguration.kt deleted file mode 100644 index 1c5d1e495..000000000 --- a/src/main/kotlin/com/exactpro/th2/common/schema/cradle/CradleConfiguration.kt +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2020-2021 Exactpro (Exactpro Systems Limited) - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.exactpro.th2.common.schema.cradle - -import com.exactpro.cradle.cassandra.CassandraStorageSettings -import com.exactpro.th2.common.schema.configuration.Configuration -import com.fasterxml.jackson.annotation.JsonProperty - -@Deprecated(message = "Please use CradleConfidentialConfiguration and CradleNonConfidentialConfiguration") -data class CradleConfiguration( - var dataCenter: String, - var host: String, - var keyspace: String, - var port: Int, - var username: String?, - var password: String?, - var cradleInstanceName: String?, - var timeout: Long, - var pageSize: Int, - var cradleMaxEventBatchSize: Long, - var cradleMaxMessageBatchSize: Long, - var prepareStorage: Boolean -) : Configuration() { - constructor( - cradleConfidentialConfiguration: CradleConfidentialConfiguration, - cradleNonConfidentialConfiguration: CradleNonConfidentialConfiguration - ) : this( - cradleConfidentialConfiguration.dataCenter, - cradleConfidentialConfiguration.host, - cradleConfidentialConfiguration.keyspace, - cradleConfidentialConfiguration.port, - cradleConfidentialConfiguration.username, - cradleConfidentialConfiguration.password, - cradleConfidentialConfiguration.cradleInstanceName, - cradleNonConfidentialConfiguration.timeout, - cradleNonConfidentialConfiguration.pageSize, - cradleNonConfidentialConfiguration.cradleMaxEventBatchSize, - cradleNonConfidentialConfiguration.cradleMaxMessageBatchSize, - cradleNonConfidentialConfiguration.prepareStorage - ) -} - -data class CradleConfidentialConfiguration( - @JsonProperty(required = true) var dataCenter: String, - @JsonProperty(required = true) var host: String, - @JsonProperty(required = true) var keyspace: String, - var port: Int = 0, - var username: String? = null, - var password: String? = null, - var cradleInstanceName: String? = null -) : Configuration() - -data class CradleNonConfidentialConfiguration( - var timeout: Long = CassandraStorageSettings.DEFAULT_TIMEOUT, - var pageSize: Int = 5000, - var cradleMaxEventBatchSize: Long = CassandraStorageSettings.DEFAULT_MAX_EVENT_BATCH_SIZE, - var cradleMaxMessageBatchSize: Long = CassandraStorageSettings.DEFAULT_MAX_MESSAGE_BATCH_SIZE, - var prepareStorage: Boolean = false -) : Configuration() \ No newline at end of file diff --git a/src/main/kotlin/com/exactpro/th2/common/schema/factory/FactorySettings.kt b/src/main/kotlin/com/exactpro/th2/common/schema/factory/FactorySettings.kt index 1712e4f07..1557fd19e 100644 --- a/src/main/kotlin/com/exactpro/th2/common/schema/factory/FactorySettings.kt +++ b/src/main/kotlin/com/exactpro/th2/common/schema/factory/FactorySettings.kt @@ -1,5 +1,5 @@ /* - * Copyright 2020-2021 Exactpro (Exactpro Systems Limited) + * Copyright 2020-2022 Exactpro (Exactpro Systems Limited) * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -15,10 +15,14 @@ package com.exactpro.th2.common.schema.factory +import com.exactpro.th2.common.ConfigurationProvider import com.exactpro.th2.common.grpc.EventBatch import com.exactpro.th2.common.grpc.MessageBatch import com.exactpro.th2.common.grpc.MessageGroupBatch import com.exactpro.th2.common.grpc.RawMessageBatch +import com.exactpro.th2.common.module.provider.FileConfigurationProvider +import com.exactpro.th2.common.module.provider.FileConfigurationProviderConfig +import com.exactpro.th2.common.schema.configuration.ConfigurationProviderConfig import com.exactpro.th2.common.schema.event.EventBatchRouter import com.exactpro.th2.common.schema.grpc.router.GrpcRouter import com.exactpro.th2.common.schema.grpc.router.impl.DefaultGrpcRouter @@ -35,13 +39,14 @@ data class FactorySettings @JvmOverloads constructor( var messageRouterMessageGroupBatchClass: Class> = RabbitMessageGroupBatchRouter::class.java, var eventBatchRouterClass: Class> = EventBatchRouter::class.java, var grpcRouterClass: Class = DefaultGrpcRouter::class.java, + var configurationProviderClass: Class = FileConfigurationProvider::class.java, + var configurationProviderConfig: ConfigurationProviderConfig = FileConfigurationProviderConfig(), + var rabbitMQ: Path? = null, var routerMQ: Path? = null, var connectionManagerSettings: Path? = null, var grpc: Path? = null, var routerGRPC: Path? = null, - var cradleConfidential: Path? = null, - var cradleNonConfidential: Path? = null, var prometheus: Path? = null, var boxConfiguration: Path? = null, var custom: Path? = null, @@ -54,4 +59,5 @@ data class FactorySettings @JvmOverloads constructor( fun putVariable(key: String, value: String): String? { return _variables.put(key, value) } + } \ No newline at end of file diff --git a/src/main/kotlin/com/exactpro/th2/common/util/CommandLineUtils.kt b/src/main/kotlin/com/exactpro/th2/common/util/CommandLineUtils.kt new file mode 100644 index 000000000..34d66d4cd --- /dev/null +++ b/src/main/kotlin/com/exactpro/th2/common/util/CommandLineUtils.kt @@ -0,0 +1,32 @@ +/* + * Copyright 2020-2022 Exactpro (Exactpro Systems Limited) + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.exactpro.th2.common.util + +import org.apache.commons.cli.Option +import org.apache.commons.cli.Options + +fun createLongOptionWithUnlimitedArgs(options: Options, optionName: String): Option { + val option = Option(null, optionName, true, null) + option.args = Option.UNLIMITED_VALUES + options.addOption(option) + return option +} + +fun createLongOption(options: Options, optionName: String): Option { + val option = Option(null, optionName, true, null) + options.addOption(option) + return option +} \ No newline at end of file diff --git a/src/test/kotlin/com/exactpro/th2/common/schema/TestJsonConfiguration.kt b/src/test/kotlin/com/exactpro/th2/common/schema/TestJsonConfiguration.kt index 16a5857b4..50df79447 100644 --- a/src/test/kotlin/com/exactpro/th2/common/schema/TestJsonConfiguration.kt +++ b/src/test/kotlin/com/exactpro/th2/common/schema/TestJsonConfiguration.kt @@ -16,18 +16,8 @@ package com.exactpro.th2.common.schema import com.exactpro.th2.common.metrics.PrometheusConfiguration -import com.exactpro.th2.common.schema.cradle.CradleConfidentialConfiguration -import com.exactpro.th2.common.schema.cradle.CradleNonConfidentialConfiguration -import com.exactpro.th2.common.schema.grpc.configuration.GrpcConfiguration -import com.exactpro.th2.common.schema.grpc.configuration.GrpcEndpointConfiguration -import com.exactpro.th2.common.schema.grpc.configuration.GrpcRawRobinStrategy -import com.exactpro.th2.common.schema.grpc.configuration.GrpcServerConfiguration -import com.exactpro.th2.common.schema.grpc.configuration.GrpcServiceConfiguration -import com.exactpro.th2.common.schema.message.configuration.FieldFilterConfiguration -import com.exactpro.th2.common.schema.message.configuration.FieldFilterOperation -import com.exactpro.th2.common.schema.message.configuration.MessageRouterConfiguration -import com.exactpro.th2.common.schema.message.configuration.MqRouterFilterConfiguration -import com.exactpro.th2.common.schema.message.configuration.QueueConfiguration +import com.exactpro.th2.common.schema.grpc.configuration.* +import com.exactpro.th2.common.schema.message.configuration.* import com.exactpro.th2.common.schema.message.impl.rabbitmq.configuration.ConnectionManagerConfiguration import com.exactpro.th2.common.schema.message.impl.rabbitmq.configuration.RabbitMQConfiguration import com.exactpro.th2.common.schema.strategy.route.impl.RobinRoutingStrategy @@ -81,26 +71,6 @@ class TestJsonConfiguration { testSerializeAndDeserialize(MESSAGE_ROUTER_CONF) } - @Test - fun `test cradle confidential json configuration deserialize`() { - testDeserialize(CRADLE_CONFIDENTIAL_CONF_JSON, CRADLE_CONFIDENTIAL_CONF) - } - - @Test - fun `test cradle confidential json configuration serialize and deserialize`() { - testSerializeAndDeserialize(CRADLE_CONFIDENTIAL_CONF) - } - - @Test - fun `test cradle non confidential json configuration deserialize`() { - testDeserialize(CRADLE_NON_CONFIDENTIAL_CONF_JSON, CRADLE_NON_CONFIDENTIAL_CONF) - } - - @Test - fun `test cradle non confidential json configuration serialize and deserialize`() { - testSerializeAndDeserialize(CRADLE_NON_CONFIDENTIAL_CONF) - } - @Test fun `test prometheus confidential json configuration deserialize`() { testDeserialize(PROMETHEUS_CONF_JSON, PROMETHEUS_CONF) @@ -202,26 +172,6 @@ class TestJsonConfiguration { }) ) - private val CRADLE_CONFIDENTIAL_CONF_JSON = loadConfJson("cradle_confidential") - private val CRADLE_CONFIDENTIAL_CONF = CradleConfidentialConfiguration( - "data center", - "host", - "keyspace", - 1234, - "user", - "pass", - "instance" - ) - - private val CRADLE_NON_CONFIDENTIAL_CONF_JSON = loadConfJson("cradle_non_confidential") - private val CRADLE_NON_CONFIDENTIAL_CONF = CradleNonConfidentialConfiguration( - 888, - 111, - 123, - 321, - false - ) - private val PROMETHEUS_CONF_JSON = loadConfJson("prometheus") private val PROMETHEUS_CONF = PrometheusConfiguration("123.3.3.3", 1234, false) diff --git a/src/test/kotlin/com/exactpro/th2/common/schema/TestModuleConfiguration.kt b/src/test/kotlin/com/exactpro/th2/common/schema/TestModuleConfiguration.kt new file mode 100644 index 000000000..9b454504a --- /dev/null +++ b/src/test/kotlin/com/exactpro/th2/common/schema/TestModuleConfiguration.kt @@ -0,0 +1,58 @@ +/* + * Copyright 2020-2022 Exactpro (Exactpro Systems Limited) + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.exactpro.th2.common.schema + +import com.exactpro.th2.common.module.provider.FileConfigurationProvider +import com.exactpro.th2.common.schema.factory.CommonFactory +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.Test + +class TestModuleConfiguration { + + @Test + fun `test configuration from command line`() { + val factory = CommonFactory.createFromArguments( + "-c", + "src/test/resources/test_module_configuration", + "-configurationProviderClass", + "com.exactpro.th2.common.module.provider.FileConfigurationProvider", + ) + + assertTrue(factory.configurationProvider is FileConfigurationProvider) + } + + @Test + fun `test configuration with provider config from command line`() { + val factory = CommonFactory.createFromArguments( + "-c", + "src/test/resources/test_module_configuration", + "-configurationProviderClass", + "com.exactpro.th2.common.module.provider.FileConfigurationProvider", + "-file-provider-extension", + "json" + ) + + assertTrue(factory.configurationProvider is FileConfigurationProvider) + } + + @Test + fun `test provider default value`() { + val factory = CommonFactory.createFromArguments("-c", "src/test/resources/test_module_configuration") + + assertTrue(factory.configurationProvider is FileConfigurationProvider) + } + +} \ No newline at end of file diff --git a/src/test/resources/test_module_configuration/prometheus.json b/src/test/resources/test_module_configuration/prometheus.json new file mode 100644 index 000000000..c994fef1c --- /dev/null +++ b/src/test/resources/test_module_configuration/prometheus.json @@ -0,0 +1,3 @@ +{ + "enabled": false +} \ No newline at end of file