From 4293919084120823f8c9c57fa36ead12216dd32d Mon Sep 17 00:00:00 2001 From: "fiodar.rekish" Date: Fri, 30 Sep 2022 21:36:08 +0400 Subject: [PATCH 1/5] [TH2-1436] dynamic config and module loading --- build.gradle | 13 +- .../FileConfigurationProviderFactoryShim.java | 29 +++++ .../schema/factory/AbstractCommonFactory.java | 109 +++------------- .../common/schema/factory/CommonFactory.java | 117 +++++++++++++----- .../provider/FileConfigurationProvider.kt | 34 +++++ .../FileConfigurationProviderFactory.kt | 89 +++++++++++++ .../schema/configuration/Configuration.kt | 30 ----- .../configuration/ConfigurationManager.kt | 50 +++++++- .../schema/cradle/CradleConfiguration.kt | 72 ----------- .../common/schema/factory/FactorySettings.kt | 64 +++++++++- .../th2/common/util/CommandLineUtils.kt | 32 +++++ .../common/schema/TestJsonConfiguration.kt | 54 +------- .../common/schema/TestModuleConfiguration.kt | 58 +++++++++ .../test_module_configuration/prometheus.json | 3 + 14 files changed, 467 insertions(+), 287 deletions(-) create mode 100644 src/main/java/com/exactpro/th2/common/module/FileConfigurationProviderFactoryShim.java create mode 100644 src/main/kotlin/com/exactpro/th2/common/module/provider/FileConfigurationProvider.kt create mode 100644 src/main/kotlin/com/exactpro/th2/common/module/provider/FileConfigurationProviderFactory.kt delete mode 100644 src/main/kotlin/com/exactpro/th2/common/schema/configuration/Configuration.kt delete mode 100644 src/main/kotlin/com/exactpro/th2/common/schema/cradle/CradleConfiguration.kt create mode 100644 src/main/kotlin/com/exactpro/th2/common/util/CommandLineUtils.kt create mode 100644 src/test/kotlin/com/exactpro/th2/common/schema/TestModuleConfiguration.kt create mode 100644 src/test/resources/test_module_configuration/prometheus.json diff --git a/build.gradle b/build.gradle index 007650c22..f623f274b 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,7 @@ buildscript { repositories { mavenCentral() + mavenLocal() } ext { @@ -37,6 +38,7 @@ ext { repositories { mavenCentral() + mavenLocal() maven { name 'Sonatype_snapshots' url 'https://s01.oss.sonatype.org/content/repositories/snapshots/' @@ -166,13 +168,18 @@ tasks.register('integrationTest', Test) { } dependencies { - api platform("com.exactpro.th2:bom:3.2.0") - api ("com.exactpro.th2:cradle-core:${cradleVersion}") + api platform("com.exactpro.th2:bom:4.0.1") 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}") + + implementation 'com.exactpro.th2:common-j-cassandra-cradle:0.1' + implementation "com.exactpro.th2:common-api-j:0.1" + + annotationProcessor 'com.google.auto.service:auto-service:1.0.1' + compileOnly 'com.google.auto.service:auto-service:1.0.1' + //FIXME: Add these dependencies as api to grpc-... artifacts implementation "io.grpc:grpc-protobuf" diff --git a/src/main/java/com/exactpro/th2/common/module/FileConfigurationProviderFactoryShim.java b/src/main/java/com/exactpro/th2/common/module/FileConfigurationProviderFactoryShim.java new file mode 100644 index 000000000..b27e11be3 --- /dev/null +++ b/src/main/java/com/exactpro/th2/common/module/FileConfigurationProviderFactoryShim.java @@ -0,0 +1,29 @@ +/* + * 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; + +import com.exactpro.th2.common.ConfigurationProviderFactory; +import com.exactpro.th2.common.module.provider.FileConfigurationProviderFactory; +import com.google.auto.service.AutoService; +import kotlin.Deprecated; +import kotlin.DeprecationLevel; + +@AutoService(ConfigurationProviderFactory.class) +@Deprecated( + message = "Don't use this class, it is only meant to be captured by ServiceLoader", + level = DeprecationLevel.HIDDEN) +public final class FileConfigurationProviderFactoryShim extends FileConfigurationProviderFactory { +} 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 533a02b65..a2e9601b7 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,18 @@ package com.exactpro.th2.common.schema.factory; +import com.exactpro.th2.common.ConfigurationProvider; +import com.exactpro.th2.common.ConfigurationProviderFactory; +import com.exactpro.th2.common.ModuleApi; 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.schema.box.configuration.BoxConfiguration; +import com.exactpro.th2.common.schema.configuration.Configuration; 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.dictionary.DictionaryType; import com.exactpro.th2.common.schema.event.EventBatchRouter; import com.exactpro.th2.common.schema.grpc.configuration.GrpcConfiguration; @@ -51,9 +54,9 @@ 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; -import org.apache.commons.io.FilenameUtils; import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -71,11 +74,14 @@ 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; import static com.exactpro.th2.common.schema.util.ArchiveUtils.getGzipBase64StringDecoder; +import static com.exactpro.th2.common.util.CommandLineUtilsKt.createLongOption; +import static com.exactpro.th2.common.util.CommandLineUtilsKt.createLongOptionWithUnlimitedArgs; import static java.util.Collections.emptyMap; import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNullElse; @@ -84,7 +90,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/"); @@ -92,12 +98,12 @@ 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 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"; +// private static final String CRADLE_NON_CONFIDENTIAL_FILE_NAME = "cradle_manager.json"; /** @deprecated please use {@link #DICTIONARY_ALIAS_DIR_NAME} */ @Deprecated @@ -117,12 +123,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, @@ -135,7 +148,9 @@ protected CommonFactory(Class> messageRout @Nullable Path dictionaryAliasesDir, @Nullable Path oldDictionariesDir, Map environmentVariables, - ConfigurationManager configurationManager) { + ConfigurationManager configurationManager, + Class configurationProviderClass, + String[] configurationProviderArgs) { super(messageRouterParsedBatchClass, messageRouterRawBatchClass, messageRouterMessageGroupBatchClass, eventBatchRouterClass, grpcRouterClass, environmentVariables); this.custom = defaultPathIfNull(custom, CUSTOM_FILE_NAME); @@ -144,6 +159,9 @@ protected CommonFactory(Class> messageRout this.oldDictionariesDir = requireNonNullElse(oldDictionariesDir, CONFIG_DEFAULT_PATH); this.configurationManager = configurationManager; + var factory = loadFactoryForProvider(configurationProviderClass); + this.configurationProvider = factory.get().initProvider(configurationProviderArgs); + start(); } @@ -158,10 +176,11 @@ public CommonFactory(FactorySettings settings) { settings.getDictionaryAliasesDir(), settings.getOldDictionariesDir(), settings.getVariables(), - createConfigurationManager(settings)); + createConfigurationManager(settings), + settings.getConfigurationProviderClass(), + settings.getConfigurationProviderArgs()); } - /** * @deprecated Please use {@link CommonFactory#CommonFactory(FactorySettings)} */ @@ -178,6 +197,8 @@ public CommonFactory(Class> messageRouterP messageRouterMessageGroupBatchClass, eventBatchRouterClass, grpcRouterClass, + FileConfigurationProvider.class, + new String[0], rabbitMQ, routerMQ, null, @@ -216,6 +237,10 @@ public CommonFactory() { this(new FactorySettings()); } + public ConfigurationProvider getConfigurationProvider() { + return configurationProvider; + } + @Override protected Path getPathToCustomConfiguration() { return custom; @@ -255,10 +280,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 @@ -269,14 +290,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: @@ -300,8 +322,6 @@ public static CommonFactory createFromArguments(String... args) { 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"); @@ -309,10 +329,13 @@ public static CommonFactory createFromArguments(String... args) { 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 dictionariesOption = createLongOptionWithUnlimitedArgs(options, "dictionaries"); Option connectionManagerConfigurationOption = createLongOption(options, "connectionManagerConfiguration"); - Option cradleManagerConfigurationOption = createLongOption(options, "cradleManagerConfiguration"); + Option configurationProviderClassOption = createLongOption(options, "configurationProviderClass"); + + configurationProviderFactoryLoader.forEach(configurationProviderFactory -> { + configurationProviderFactory.addOwnOptionsToCmd(options); + }); try { CommandLine cmd = new DefaultParser().parse(options, args); @@ -357,8 +380,6 @@ public static CommonFactory createFromArguments(String... args) { 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)); @@ -367,10 +388,52 @@ public static CommonFactory createFromArguments(String... args) { String oldDictionariesDir = cmd.getOptionValue(dictionariesDirOption.getLongOpt()); settings.setOldDictionariesDir(oldDictionariesDir == null ? (configs == null ? CONFIG_DEFAULT_PATH : Path.of(configs)) : Path.of(oldDictionariesDir)); + String configurationProviderClassName = cmd.getOptionValue(configurationProviderClassOption.getLongOpt(), + DEFAULT_CONFIGURATION_PROVIDER.getName()); + var providerClass = (Class) Class.forName(configurationProviderClassName); + var factory = loadFactoryForProvider(providerClass); + String[] providerArguments = factory.get().parseCommandLine(cmd); + settings.setConfigurationProviderClass(providerClass); + settings.setConfigurationProviderArgs(providerArguments); + return new CommonFactory(settings); } catch (ParseException e) { throw new IllegalArgumentException("Incorrect arguments " + Arrays.toString(args), e); + } catch (ClassNotFoundException e) { + LOGGER.error("Failed to find configuration provider class: " + e.getMessage()); + throw new IllegalArgumentException("Incorrect arguments " + Arrays.toString(args), e); + } + } + + private static ServiceLoader.@NotNull Provider loadFactoryForProvider( + Class providerClass) { + + var optionalFactory = configurationProviderFactoryLoader.stream() + .filter(factory -> factory.get().getType().equals(providerClass)) + .findFirst(); + if (optionalFactory.isEmpty()) { + LOGGER.error("Cannot find provider {}", providerClass); + throw new IllegalArgumentException("Cannot find provider " + providerClass); } + return optionalFactory.get(); + } + + @Override + public 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); + } + + @Override + public @NotNull C loadConfiguration(@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.getConfigurationWithConfigurationProvider(clazz, configurationProvider); } /** @@ -481,8 +544,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)); @@ -689,8 +750,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); @@ -713,12 +772,6 @@ 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)); } 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..c24d15b81 --- /dev/null +++ b/src/main/kotlin/com/exactpro/th2/common/module/provider/FileConfigurationProvider.kt @@ -0,0 +1,34 @@ +/* + * 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.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/FileConfigurationProviderFactory.kt b/src/main/kotlin/com/exactpro/th2/common/module/provider/FileConfigurationProviderFactory.kt new file mode 100644 index 000000000..580981951 --- /dev/null +++ b/src/main/kotlin/com/exactpro/th2/common/module/provider/FileConfigurationProviderFactory.kt @@ -0,0 +1,89 @@ +/* + * 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.strategy.route.json.RoutingStrategyModule +import com.exactpro.th2.common.util.createLongOption +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule +import com.fasterxml.jackson.module.kotlin.registerKotlinModule +import org.apache.commons.cli.CommandLine +import org.apache.commons.cli.Options + +open class FileConfigurationProviderFactory: ConfigurationProviderFactory { + + private val objectMapper: ObjectMapper = ObjectMapper() + + init { + objectMapper.registerKotlinModule() + objectMapper.registerModules( + RoutingStrategyModule(objectMapper), + JavaTimeModule() + ) + } + + override val type: Class + get() = FileConfigurationProvider::class.java + + /** + * Adds options to [Options] + * + * See [companion object of this class][Companion] + */ + override fun addOwnOptionsToCmd(options: Options) { + createLongOption(options, PATH_OPTION) + createLongOption(options, EXTENSION_OPTION) + } + + /** + * Parses [CommandLine] object. + * + * You can check parameters names ane their default values in [companion object of this class][Companion]. + */ + override fun parseCommandLine(cmd: CommandLine): Array { + return arrayOf( + cmd.getOptionValue(PATH_OPTION, DEFAULT_PATH), + cmd.getOptionValue(EXTENSION_OPTION, DEFAULT_EXTENSION) + ) + } + + /** + * Accepts two parameters: + * + * args[0] - directory where provider will search files + * args[1] - extension of file without dot + */ + override fun initProvider(args: Array): ConfigurationProvider { + val firstParam = args.getOrNull(0) + val secondParam = args.getOrNull(1) + + return FileConfigurationProvider(objectMapper, + configurationDir = firstParam ?: DEFAULT_PATH, + fileExtension = secondParam ?: DEFAULT_EXTENSION + ) + } + + companion object { + const val PATH_OPTION = "file-provider-path" + const val EXTENSION_OPTION = "file-provider-extension" + + const val DEFAULT_PATH = "/opt/th2/config" + const val DEFAULT_EXTENSION = "json" + } + +} \ 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..d52224d6b 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,32 @@ package com.exactpro.th2.common.schema.configuration +import com.exactpro.th2.common.ConfigurationProvider +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.* import java.util.concurrent.ConcurrentHashMap class ConfigurationManager(private val configurationPath: Map, Path>) { - private val configurations: MutableMap, Any?> = ConcurrentHashMap() + private val cache: MutableMap, Any?> = ConcurrentHashMap() + private val modulesFactoryMapping: MutableMap, ModuleFactory> = ConcurrentHashMap() + private val configurationFactoryMapping: MutableMap, ModuleFactory> = ConcurrentHashMap() + + init { + ServiceLoader.load(ModuleFactory::class.java).forEach { moduleFactory -> + moduleFactory.configurationClasses.forEach { + configurationFactoryMapping[it] = moduleFactory + } + moduleFactory.moduleClasses.forEach { + modulesFactoryMapping[it] = moduleFactory + } + } + } fun loadConfiguration( objectMapper: ObjectMapper, @@ -48,13 +64,41 @@ class ConfigurationManager(private val configurationPath: Map, Path>) { } } + fun getModuleWithConfigurationProvider( + moduleClass: Class, + configurationProvider: ConfigurationProvider + ): T { + val moduleFactory: ModuleFactory? = modulesFactoryMapping[moduleClass] + checkNotNull(moduleFactory) { + LOGGER.error { "Mapping does not contain module factory for $moduleClass" } + "Mapping does not contain module factory for $moduleClass" + } + val module: T = moduleFactory.loadModule(configurationProvider, moduleClass) as T + checkNotNull(module) { + LOGGER.error { "Returned null instead of instance of class $moduleClass" } + "Returned null instead of instance of class $moduleClass" + } + return module + } + + fun getConfigurationWithConfigurationProvider( + configClass: Class, + configurationProvider: ConfigurationProvider + ): T { + return cache.computeIfAbsent(configClass) { + checkNotNull(configurationFactoryMapping[configClass]) { + "Unknown class $configClass" + }.loadConfiguration(configurationProvider, configClass) + } as T + } + fun getConfigurationOrLoad( objectMapper: ObjectMapper, stringSubstitutor: StringSubstitutor, configClass: Class, optional: Boolean ): T { - return configurations.computeIfAbsent(configClass) { + return cache.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..709cd624a 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,12 @@ 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.schema.event.EventBatchRouter import com.exactpro.th2.common.schema.grpc.router.GrpcRouter import com.exactpro.th2.common.schema.grpc.router.impl.DefaultGrpcRouter @@ -35,13 +37,15 @@ data class FactorySettings @JvmOverloads constructor( var messageRouterMessageGroupBatchClass: Class> = RabbitMessageGroupBatchRouter::class.java, var eventBatchRouterClass: Class> = EventBatchRouter::class.java, var grpcRouterClass: Class = DefaultGrpcRouter::class.java, +// var configurationProvider: ConfigurationProvider? = null, + var configurationProviderClass: Class = FileConfigurationProvider::class.java, + var configurationProviderArgs: Array = emptyArray(), + 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 +58,58 @@ data class FactorySettings @JvmOverloads constructor( fun putVariable(key: String, value: String): String? { return _variables.put(key, value) } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as FactorySettings + + if (messageRouterParsedBatchClass != other.messageRouterParsedBatchClass) return false + if (messageRouterRawBatchClass != other.messageRouterRawBatchClass) return false + if (messageRouterMessageGroupBatchClass != other.messageRouterMessageGroupBatchClass) return false + if (eventBatchRouterClass != other.eventBatchRouterClass) return false + if (grpcRouterClass != other.grpcRouterClass) return false + if (configurationProviderClass != other.configurationProviderClass) return false + if (!configurationProviderArgs.contentEquals(other.configurationProviderArgs)) return false + if (rabbitMQ != other.rabbitMQ) return false + if (routerMQ != other.routerMQ) return false + if (connectionManagerSettings != other.connectionManagerSettings) return false + if (grpc != other.grpc) return false + if (routerGRPC != other.routerGRPC) return false + if (prometheus != other.prometheus) return false + if (boxConfiguration != other.boxConfiguration) return false + if (custom != other.custom) return false + if (dictionaryTypesDir != other.dictionaryTypesDir) return false + if (dictionaryAliasesDir != other.dictionaryAliasesDir) return false + if (oldDictionariesDir != other.oldDictionariesDir) return false + if (_variables != other._variables) return false + if (variables != other.variables) return false + + return true + } + + override fun hashCode(): Int { + var result = messageRouterParsedBatchClass.hashCode() + result = 31 * result + messageRouterRawBatchClass.hashCode() + result = 31 * result + messageRouterMessageGroupBatchClass.hashCode() + result = 31 * result + eventBatchRouterClass.hashCode() + result = 31 * result + grpcRouterClass.hashCode() + result = 31 * result + configurationProviderClass.hashCode() + result = 31 * result + configurationProviderArgs.contentHashCode() + result = 31 * result + (rabbitMQ?.hashCode() ?: 0) + result = 31 * result + (routerMQ?.hashCode() ?: 0) + result = 31 * result + (connectionManagerSettings?.hashCode() ?: 0) + result = 31 * result + (grpc?.hashCode() ?: 0) + result = 31 * result + (routerGRPC?.hashCode() ?: 0) + result = 31 * result + (prometheus?.hashCode() ?: 0) + result = 31 * result + (boxConfiguration?.hashCode() ?: 0) + result = 31 * result + (custom?.hashCode() ?: 0) + result = 31 * result + (dictionaryTypesDir?.hashCode() ?: 0) + result = 31 * result + (dictionaryAliasesDir?.hashCode() ?: 0) + result = 31 * result + (oldDictionariesDir?.hashCode() ?: 0) + result = 31 * result + _variables.hashCode() + result = 31 * result + variables.hashCode() + return result + } } \ 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 From fb7afa6843e691be72e22804d762812725030947 Mon Sep 17 00:00:00 2001 From: "fiodar.rekish" Date: Tue, 4 Oct 2022 14:56:41 +0400 Subject: [PATCH 2/5] [TH2-1436] version update, small changes --- README.md | 8 +++++++- build.gradle | 6 ++---- gradle.properties | 2 +- .../exactpro/th2/common/schema/factory/CommonFactory.java | 2 +- .../common/module/provider/FileConfigurationProvider.kt | 3 ++- .../module/provider/FileConfigurationProviderFactory.kt | 2 +- .../common/schema/configuration/ConfigurationManager.kt | 2 +- 7 files changed, 15 insertions(+), 10 deletions(-) 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 ef2ca8df4..a0aba8ead 100644 --- a/build.gradle +++ b/build.gradle @@ -1,8 +1,6 @@ buildscript { repositories { mavenCentral() - // todo remove - mavenLocal() } ext { @@ -176,8 +174,8 @@ dependencies { implementation 'com.google.protobuf:protobuf-java-util' implementation 'com.exactpro.th2:grpc-service-generator:3.2.2' - implementation 'com.exactpro.th2:common-j-cassandra-cradle:0.1' - implementation "com.exactpro.th2:common-api-j:0.1" + implementation 'com.exactpro.th2:common-j-cassandra-cradle:0.0.1-th2-1436-init-3181374693-6b81dc9-SNAPSHOT' + implementation "com.exactpro.th2:common-api-j:0.0.1-th2-1436-init-3180908004-e67b670-SNAPSHOT" annotationProcessor 'com.google.auto.service:auto-service:1.0.1' compileOnly 'com.google.auto.service:auto-service:1.0.1' 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/CommonFactory.java b/src/main/java/com/exactpro/th2/common/schema/factory/CommonFactory.java index 42358b5b1..89fb83d0b 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 @@ -159,7 +159,7 @@ protected CommonFactory(Class> messageRout this.configurationManager = configurationManager; var factory = loadFactoryForProvider(configurationProviderClass); - this.configurationProvider = factory.get().initProvider(configurationProviderArgs); + this.configurationProvider = factory.get().createProvider(configurationProviderArgs); start(); } 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 index c24d15b81..fb492510a 100644 --- a/src/main/kotlin/com/exactpro/th2/common/module/provider/FileConfigurationProvider.kt +++ b/src/main/kotlin/com/exactpro/th2/common/module/provider/FileConfigurationProvider.kt @@ -16,6 +16,7 @@ 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 @@ -27,7 +28,7 @@ class FileConfigurationProvider( ) : ConfigurationProvider { - override fun loadConfiguration(configId: String, cfgClass: Class): C { + override fun loadConfiguration(configId: String, cfgClass: Class): C { return objectMapper.readValue(Paths.get(configurationDir, "$configId.$fileExtension").toFile(), cfgClass) } 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 index 580981951..83ab9eb51 100644 --- a/src/main/kotlin/com/exactpro/th2/common/module/provider/FileConfigurationProviderFactory.kt +++ b/src/main/kotlin/com/exactpro/th2/common/module/provider/FileConfigurationProviderFactory.kt @@ -68,7 +68,7 @@ open class FileConfigurationProviderFactory: ConfigurationProviderFactory { * args[0] - directory where provider will search files * args[1] - extension of file without dot */ - override fun initProvider(args: Array): ConfigurationProvider { + override fun createProvider(args: Array): ConfigurationProvider { val firstParam = args.getOrNull(0) val secondParam = args.getOrNull(1) 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 d52224d6b..dd92f2e84 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 @@ -81,7 +81,7 @@ class ConfigurationManager(private val configurationPath: Map, Path>) { return module } - fun getConfigurationWithConfigurationProvider( + fun getConfigurationWithConfigurationProvider( configClass: Class, configurationProvider: ConfigurationProvider ): T { From 7b8c63578530c0a53454bd6dff9838d01a44361f Mon Sep 17 00:00:00 2001 From: "fiodar.rekish" Date: Tue, 29 Nov 2022 18:04:19 +0400 Subject: [PATCH 3/5] [TH2-1436] using jcommander for cli parsing --- build.gradle | 9 +- .../common/schema/factory/CommonFactory.java | 138 ++++++++---------- .../th2/common/cli/CommonFactoryArgs.kt | 71 +++++++++ .../FileConfigurationProviderConfig.kt | 32 ++++ .../FileConfigurationProviderFactory.kt | 61 ++------ .../configuration/ConfigurationManager.kt | 35 +---- .../common/schema/factory/FactorySettings.kt | 58 +------- 7 files changed, 192 insertions(+), 212 deletions(-) create mode 100644 src/main/kotlin/com/exactpro/th2/common/cli/CommonFactoryArgs.kt create mode 100644 src/main/kotlin/com/exactpro/th2/common/module/provider/FileConfigurationProviderConfig.kt diff --git a/build.gradle b/build.gradle index a0aba8ead..209357411 100644 --- a/build.gradle +++ b/build.gradle @@ -174,12 +174,17 @@ dependencies { implementation 'com.google.protobuf:protobuf-java-util' implementation 'com.exactpro.th2:grpc-service-generator:3.2.2' - implementation 'com.exactpro.th2:common-j-cassandra-cradle:0.0.1-th2-1436-init-3181374693-6b81dc9-SNAPSHOT' - implementation "com.exactpro.th2:common-api-j:0.0.1-th2-1436-init-3180908004-e67b670-SNAPSHOT" + // 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-th2-1436-init-3574652642-d3de09f-SNAPSHOT" annotationProcessor 'com.google.auto.service:auto-service:1.0.1' compileOnly 'com.google.auto.service:auto-service:1.0.1' + implementation 'com.beust:jcommander:1.82' + implementation "commons-cli:commons-cli" //FIXME: Add these dependencies as api to grpc-... artifacts implementation "io.grpc:grpc-protobuf" 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 89fb83d0b..0dd86bfc6 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,18 +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.Configuration; import com.exactpro.th2.common.schema.configuration.ConfigurationManager; +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; @@ -48,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; @@ -79,8 +78,6 @@ import java.util.stream.Stream; import static com.exactpro.th2.common.schema.util.ArchiveUtils.getGzipBase64StringDecoder; -import static com.exactpro.th2.common.util.CommandLineUtilsKt.createLongOption; -import static com.exactpro.th2.common.util.CommandLineUtilsKt.createLongOptionWithUnlimitedArgs; import static java.util.Collections.emptyMap; import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNullElse; @@ -97,12 +94,10 @@ public class CommonFactory extends AbstractCommonFactory implements ModuleApi { 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 @@ -149,7 +144,7 @@ protected CommonFactory(Class> messageRout Map environmentVariables, ConfigurationManager configurationManager, Class configurationProviderClass, - String[] configurationProviderArgs) { + ConfigurationProviderConfig providerConfig) { super(messageRouterParsedBatchClass, messageRouterRawBatchClass, messageRouterMessageGroupBatchClass, eventBatchRouterClass, grpcRouterClass, environmentVariables); this.custom = defaultPathIfNull(custom, CUSTOM_FILE_NAME); @@ -159,7 +154,7 @@ protected CommonFactory(Class> messageRout this.configurationManager = configurationManager; var factory = loadFactoryForProvider(configurationProviderClass); - this.configurationProvider = factory.get().createProvider(configurationProviderArgs); + this.configurationProvider = factory.get().create(providerConfig); start(); } @@ -177,7 +172,7 @@ public CommonFactory(FactorySettings settings) { settings.getVariables(), createConfigurationManager(settings), settings.getConfigurationProviderClass(), - settings.getConfigurationProviderArgs()); + settings.getConfigurationProviderConfig()); } /** @@ -197,7 +192,7 @@ public CommonFactory(Class> messageRouterP eventBatchRouterClass, grpcRouterClass, FileConfigurationProvider.class, - new String[0], + new FileConfigurationProviderConfig(), rabbitMQ, routerMQ, null, @@ -311,48 +306,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 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 = createLongOptionWithUnlimitedArgs(options, "dictionaries"); - Option connectionManagerConfigurationOption = createLongOption(options, "connectionManagerConfiguration"); - Option configurationProviderClassOption = createLongOption(options, "configurationProviderClass"); - - configurationProviderFactoryLoader.forEach(configurationProviderFactory -> { - configurationProviderFactory.addOwnOptionsToCmd(options); - }); 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(); @@ -367,43 +335,65 @@ 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.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 = cmd.getOptionValue(configurationProviderClassOption.getLongOpt(), - DEFAULT_CONFIGURATION_PROVIDER.getName()); + String configurationProviderClassName = defaultIfNull(parsedArgs.configurationProviderClass, DEFAULT_CONFIGURATION_PROVIDER.getName()); + var providerClass = (Class) Class.forName(configurationProviderClassName); var factory = loadFactoryForProvider(providerClass); - String[] providerArguments = factory.get().parseCommandLine(cmd); + ConfigurationProviderFactory configurationProviderFactory = factory.get(); + + + ConfigurationProviderConfig configurationProviderConfig = + parseAs(args, configurationProviderFactory.settings()); + settings.setConfigurationProviderClass(providerClass); - settings.setConfigurationProviderArgs(providerArguments); + settings.setConfigurationProviderConfig(configurationProviderConfig); return new CommonFactory(settings); - } catch (ParseException e) { - throw new IllegalArgumentException("Incorrect arguments " + Arrays.toString(args), e); } catch (ClassNotFoundException e) { LOGGER.error("Failed to find configuration provider class: " + e.getMessage()); throw new IllegalArgumentException("Incorrect arguments " + Arrays.toString(args), 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; + } + private static ServiceLoader.@NotNull Provider loadFactoryForProvider( Class providerClass) { @@ -418,7 +408,7 @@ public static CommonFactory createFromArguments(String... args) { } @Override - public M loadModule(@NotNull Class clazz) { + 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"); @@ -426,14 +416,6 @@ public M loadModule(@NotNull Class clazz) { return configurationManager.getModuleWithConfigurationProvider(clazz, configurationProvider); } - @Override - public @NotNull C loadConfiguration(@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.getConfigurationWithConfigurationProvider(clazz, configurationProvider); - } /** * Create {@link CommonFactory} via configs map from Kubernetes @@ -775,11 +757,7 @@ private static Path calculatePath(String path, String configsPath, String fileNa 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/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 index 83ab9eb51..6a0cd1393 100644 --- a/src/main/kotlin/com/exactpro/th2/common/module/provider/FileConfigurationProviderFactory.kt +++ b/src/main/kotlin/com/exactpro/th2/common/module/provider/FileConfigurationProviderFactory.kt @@ -17,15 +17,13 @@ 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.exactpro.th2.common.util.createLongOption import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule import com.fasterxml.jackson.module.kotlin.registerKotlinModule -import org.apache.commons.cli.CommandLine -import org.apache.commons.cli.Options -open class FileConfigurationProviderFactory: ConfigurationProviderFactory { +open class FileConfigurationProviderFactory : ConfigurationProviderFactory { private val objectMapper: ObjectMapper = ObjectMapper() @@ -40,50 +38,19 @@ open class FileConfigurationProviderFactory: ConfigurationProviderFactory { override val type: Class get() = FileConfigurationProvider::class.java - /** - * Adds options to [Options] - * - * See [companion object of this class][Companion] - */ - override fun addOwnOptionsToCmd(options: Options) { - createLongOption(options, PATH_OPTION) - createLongOption(options, EXTENSION_OPTION) + override fun create(config: ConfigurationProviderConfig): ConfigurationProvider { + if (config is FileConfigurationProviderConfig) { + return FileConfigurationProvider( + objectMapper, + config.fileProviderPath, + config.fileProviderExtension + ) + } else { + throw IllegalArgumentException() + } } - /** - * Parses [CommandLine] object. - * - * You can check parameters names ane their default values in [companion object of this class][Companion]. - */ - override fun parseCommandLine(cmd: CommandLine): Array { - return arrayOf( - cmd.getOptionValue(PATH_OPTION, DEFAULT_PATH), - cmd.getOptionValue(EXTENSION_OPTION, DEFAULT_EXTENSION) - ) - } - - /** - * Accepts two parameters: - * - * args[0] - directory where provider will search files - * args[1] - extension of file without dot - */ - override fun createProvider(args: Array): ConfigurationProvider { - val firstParam = args.getOrNull(0) - val secondParam = args.getOrNull(1) - - return FileConfigurationProvider(objectMapper, - configurationDir = firstParam ?: DEFAULT_PATH, - fileExtension = secondParam ?: DEFAULT_EXTENSION - ) + override fun settings(): ConfigurationProviderConfig { + return FileConfigurationProviderConfig() } - - companion object { - const val PATH_OPTION = "file-provider-path" - const val EXTENSION_OPTION = "file-provider-extension" - - const val DEFAULT_PATH = "/opt/th2/config" - const val DEFAULT_EXTENSION = "json" - } - } \ 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 dd92f2e84..3325233aa 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 @@ -16,29 +16,24 @@ 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.* +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 cache: MutableMap, Any?> = ConcurrentHashMap() private val modulesFactoryMapping: MutableMap, ModuleFactory> = ConcurrentHashMap() - private val configurationFactoryMapping: MutableMap, ModuleFactory> = ConcurrentHashMap() init { ServiceLoader.load(ModuleFactory::class.java).forEach { moduleFactory -> - moduleFactory.configurationClasses.forEach { - configurationFactoryMapping[it] = moduleFactory - } - moduleFactory.moduleClasses.forEach { - modulesFactoryMapping[it] = moduleFactory - } + modulesFactoryMapping[moduleFactory.moduleType] = moduleFactory } } @@ -64,7 +59,7 @@ class ConfigurationManager(private val configurationPath: Map, Path>) { } } - fun getModuleWithConfigurationProvider( + fun getModuleWithConfigurationProvider( moduleClass: Class, configurationProvider: ConfigurationProvider ): T { @@ -73,23 +68,7 @@ class ConfigurationManager(private val configurationPath: Map, Path>) { LOGGER.error { "Mapping does not contain module factory for $moduleClass" } "Mapping does not contain module factory for $moduleClass" } - val module: T = moduleFactory.loadModule(configurationProvider, moduleClass) as T - checkNotNull(module) { - LOGGER.error { "Returned null instead of instance of class $moduleClass" } - "Returned null instead of instance of class $moduleClass" - } - return module - } - - fun getConfigurationWithConfigurationProvider( - configClass: Class, - configurationProvider: ConfigurationProvider - ): T { - return cache.computeIfAbsent(configClass) { - checkNotNull(configurationFactoryMapping[configClass]) { - "Unknown class $configClass" - }.loadConfiguration(configurationProvider, configClass) - } as T + return moduleFactory.create(configurationProvider) as T } fun getConfigurationOrLoad( 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 709cd624a..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 @@ -21,6 +21,8 @@ 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 @@ -37,9 +39,8 @@ data class FactorySettings @JvmOverloads constructor( var messageRouterMessageGroupBatchClass: Class> = RabbitMessageGroupBatchRouter::class.java, var eventBatchRouterClass: Class> = EventBatchRouter::class.java, var grpcRouterClass: Class = DefaultGrpcRouter::class.java, -// var configurationProvider: ConfigurationProvider? = null, var configurationProviderClass: Class = FileConfigurationProvider::class.java, - var configurationProviderArgs: Array = emptyArray(), + var configurationProviderConfig: ConfigurationProviderConfig = FileConfigurationProviderConfig(), var rabbitMQ: Path? = null, var routerMQ: Path? = null, @@ -59,57 +60,4 @@ data class FactorySettings @JvmOverloads constructor( return _variables.put(key, value) } - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false - - other as FactorySettings - - if (messageRouterParsedBatchClass != other.messageRouterParsedBatchClass) return false - if (messageRouterRawBatchClass != other.messageRouterRawBatchClass) return false - if (messageRouterMessageGroupBatchClass != other.messageRouterMessageGroupBatchClass) return false - if (eventBatchRouterClass != other.eventBatchRouterClass) return false - if (grpcRouterClass != other.grpcRouterClass) return false - if (configurationProviderClass != other.configurationProviderClass) return false - if (!configurationProviderArgs.contentEquals(other.configurationProviderArgs)) return false - if (rabbitMQ != other.rabbitMQ) return false - if (routerMQ != other.routerMQ) return false - if (connectionManagerSettings != other.connectionManagerSettings) return false - if (grpc != other.grpc) return false - if (routerGRPC != other.routerGRPC) return false - if (prometheus != other.prometheus) return false - if (boxConfiguration != other.boxConfiguration) return false - if (custom != other.custom) return false - if (dictionaryTypesDir != other.dictionaryTypesDir) return false - if (dictionaryAliasesDir != other.dictionaryAliasesDir) return false - if (oldDictionariesDir != other.oldDictionariesDir) return false - if (_variables != other._variables) return false - if (variables != other.variables) return false - - return true - } - - override fun hashCode(): Int { - var result = messageRouterParsedBatchClass.hashCode() - result = 31 * result + messageRouterRawBatchClass.hashCode() - result = 31 * result + messageRouterMessageGroupBatchClass.hashCode() - result = 31 * result + eventBatchRouterClass.hashCode() - result = 31 * result + grpcRouterClass.hashCode() - result = 31 * result + configurationProviderClass.hashCode() - result = 31 * result + configurationProviderArgs.contentHashCode() - result = 31 * result + (rabbitMQ?.hashCode() ?: 0) - result = 31 * result + (routerMQ?.hashCode() ?: 0) - result = 31 * result + (connectionManagerSettings?.hashCode() ?: 0) - result = 31 * result + (grpc?.hashCode() ?: 0) - result = 31 * result + (routerGRPC?.hashCode() ?: 0) - result = 31 * result + (prometheus?.hashCode() ?: 0) - result = 31 * result + (boxConfiguration?.hashCode() ?: 0) - result = 31 * result + (custom?.hashCode() ?: 0) - result = 31 * result + (dictionaryTypesDir?.hashCode() ?: 0) - result = 31 * result + (dictionaryAliasesDir?.hashCode() ?: 0) - result = 31 * result + (oldDictionariesDir?.hashCode() ?: 0) - result = 31 * result + _variables.hashCode() - result = 31 * result + variables.hashCode() - return result - } } \ No newline at end of file From ed81c24860220f08eb1a31a7c5c2d793c40bbc7e Mon Sep 17 00:00:00 2001 From: "fiodar.rekish" Date: Thu, 1 Dec 2022 13:00:29 +0400 Subject: [PATCH 4/5] [TH2-1436] modules caching, creating config for ConfigurationProvider via reflection --- build.gradle | 3 +-- .../common/schema/factory/CommonFactory.java | 16 ++++++++++------ .../FileConfigurationProviderFactory.kt | 9 +++++---- .../configuration/ConfigurationManager.kt | 17 +++++++++-------- 4 files changed, 25 insertions(+), 20 deletions(-) diff --git a/build.gradle b/build.gradle index 209357411..bbe63db5d 100644 --- a/build.gradle +++ b/build.gradle @@ -178,13 +178,12 @@ dependencies { // 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-th2-1436-init-3574652642-d3de09f-SNAPSHOT" + 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' implementation 'com.beust:jcommander:1.82' - implementation "commons-cli:commons-cli" //FIXME: Add these dependencies as api to grpc-... artifacts implementation "io.grpc:grpc-protobuf" 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 0dd86bfc6..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 @@ -65,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; @@ -363,7 +364,7 @@ public static CommonFactory createFromArguments(String... args) { ConfigurationProviderConfig configurationProviderConfig = - parseAs(args, configurationProviderFactory.settings()); + parseAs(args, configurationProviderFactory.getConfigClass().getDeclaredConstructor().newInstance()); settings.setConfigurationProviderClass(providerClass); settings.setConfigurationProviderConfig(configurationProviderConfig); @@ -372,6 +373,9 @@ public static CommonFactory createFromArguments(String... args) { } 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); } } @@ -394,17 +398,17 @@ private static CommonFactoryArgs parseAsCommonConfig(String[] args) { return commonFactoryArgs; } - private static ServiceLoader.@NotNull Provider loadFactoryForProvider( + @NotNull + private static ServiceLoader.Provider loadFactoryForProvider( Class providerClass) { var optionalFactory = configurationProviderFactoryLoader.stream() .filter(factory -> factory.get().getType().equals(providerClass)) .findFirst(); - if (optionalFactory.isEmpty()) { + return optionalFactory.orElseThrow(() -> { LOGGER.error("Cannot find provider {}", providerClass); - throw new IllegalArgumentException("Cannot find provider " + providerClass); - } - return optionalFactory.get(); + return new IllegalArgumentException("Cannot find provider " + providerClass); + }); } @Override 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 index 6a0cd1393..4acbc8105 100644 --- a/src/main/kotlin/com/exactpro/th2/common/module/provider/FileConfigurationProviderFactory.kt +++ b/src/main/kotlin/com/exactpro/th2/common/module/provider/FileConfigurationProviderFactory.kt @@ -35,9 +35,13 @@ open class FileConfigurationProviderFactory : ConfigurationProviderFactory { ) } + 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( @@ -46,11 +50,8 @@ open class FileConfigurationProviderFactory : ConfigurationProviderFactory { config.fileProviderExtension ) } else { - throw IllegalArgumentException() + throw IllegalArgumentException("Wrong provider config: expected FileConfigurationProviderConfig, actual ${config::class.java}") } } - override fun settings(): ConfigurationProviderConfig { - return FileConfigurationProviderConfig() - } } \ 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 3325233aa..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 @@ -28,7 +28,8 @@ import mu.KotlinLogging import org.apache.commons.text.StringSubstitutor class ConfigurationManager(private val configurationPath: Map, Path>) { - private val cache: MutableMap, Any?> = ConcurrentHashMap() + private val configurationCache: MutableMap, Any?> = ConcurrentHashMap() + private val moduleCache: MutableMap, Module> = ConcurrentHashMap() private val modulesFactoryMapping: MutableMap, ModuleFactory> = ConcurrentHashMap() init { @@ -63,12 +64,12 @@ class ConfigurationManager(private val configurationPath: Map, Path>) { moduleClass: Class, configurationProvider: ConfigurationProvider ): T { - val moduleFactory: ModuleFactory? = modulesFactoryMapping[moduleClass] - checkNotNull(moduleFactory) { - LOGGER.error { "Mapping does not contain module factory for $moduleClass" } - "Mapping does not contain module factory for $moduleClass" - } - return moduleFactory.create(configurationProvider) as 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( @@ -77,7 +78,7 @@ class ConfigurationManager(private val configurationPath: Map, Path>) { configClass: Class, optional: Boolean ): T { - return cache.computeIfAbsent(configClass) { + return configurationCache.computeIfAbsent(configClass) { checkNotNull(configurationPath[configClass]) { "Unknown class $configClass" }.let { From 07dc700896e5114b9b0eb78a10dfd3ce8194d4c8 Mon Sep 17 00:00:00 2001 From: "fiodar.rekish" Date: Thu, 1 Dec 2022 13:59:33 +0400 Subject: [PATCH 5/5] [TH2-1436] added kapt plugin --- build.gradle | 2 ++ .../FileConfigurationProviderFactoryShim.java | 29 ------------------- .../FileConfigurationProviderFactory.kt | 2 ++ 3 files changed, 4 insertions(+), 29 deletions(-) delete mode 100644 src/main/java/com/exactpro/th2/common/module/FileConfigurationProviderFactoryShim.java diff --git a/build.gradle b/build.gradle index bbe63db5d..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" } @@ -182,6 +183,7 @@ dependencies { 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' diff --git a/src/main/java/com/exactpro/th2/common/module/FileConfigurationProviderFactoryShim.java b/src/main/java/com/exactpro/th2/common/module/FileConfigurationProviderFactoryShim.java deleted file mode 100644 index b27e11be3..000000000 --- a/src/main/java/com/exactpro/th2/common/module/FileConfigurationProviderFactoryShim.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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; - -import com.exactpro.th2.common.ConfigurationProviderFactory; -import com.exactpro.th2.common.module.provider.FileConfigurationProviderFactory; -import com.google.auto.service.AutoService; -import kotlin.Deprecated; -import kotlin.DeprecationLevel; - -@AutoService(ConfigurationProviderFactory.class) -@Deprecated( - message = "Don't use this class, it is only meant to be captured by ServiceLoader", - level = DeprecationLevel.HIDDEN) -public final class FileConfigurationProviderFactoryShim extends FileConfigurationProviderFactory { -} 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 index 4acbc8105..5ca297a1d 100644 --- a/src/main/kotlin/com/exactpro/th2/common/module/provider/FileConfigurationProviderFactory.kt +++ b/src/main/kotlin/com/exactpro/th2/common/module/provider/FileConfigurationProviderFactory.kt @@ -22,7 +22,9 @@ 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()