All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.helidon.config.MetaConfig Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2019, 2024 Oracle and/or its affiliates.
 *
 * 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 io.helidon.config;

import java.lang.System.Logger.Level;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.ServiceLoader;
import java.util.Set;
import java.util.function.Function;

import io.helidon.common.HelidonServiceLoader;
import io.helidon.common.media.type.MediaType;
import io.helidon.config.spi.ChangeWatcher;
import io.helidon.config.spi.ConfigParser;
import io.helidon.config.spi.ConfigSource;
import io.helidon.config.spi.OverrideSource;
import io.helidon.config.spi.PollingStrategy;
import io.helidon.config.spi.RetryPolicy;
import io.helidon.service.registry.Service;

/**
 * Meta configuration.
 * 

* Configuration allows configuring itself using meta configuration. * Config looks for {@code meta-config.*} files in the current directory and on the classpath, where the {@code *} is * one of the supported media type suffixes (such as {@code yaml} when {@code helidon-config-yaml} module is on the classpath). *

* Meta configuration can define which config sources to load, including possible retry policy, polling strategy and change * watchers. *

* Example of a YAML meta configuration file: *

 * sources:
 *   - type: "environment-variables"
 *   - type: "system-properties"
 *   - type: "file"
 *     properties:
 *       path: "conf/dev.yaml"
 *       optional: true
 *   - type: "file"
 *     properties:
 *       path: "conf/config.yaml"
 *       optional: true
 *   - type: "classpath"
 *     properties:
 *       resource: "default.yaml"
 * 
* This configuration would load the following config sources (in the order specified): *
    *
  • Environment variables config source *
  • System properties config source
  • *
  • File config source from file {@code conf/dev.yaml} that is optional
  • *
  • File config source from file {@code conf/config.yaml} that is optional
  • *
  • Classpath resource config source for resource {@code default.yaml} that is mandatory
  • *
*/ @Service.Provider public final class MetaConfig { private static final System.Logger LOGGER = System.getLogger(MetaConfig.class.getName()); private static final Set SUPPORTED_MEDIA_TYPES; private static final List SUPPORTED_SUFFIXES; static { Set supportedMediaTypes = new HashSet<>(); List supportedSuffixes = new LinkedList<>(); HelidonServiceLoader.create(ServiceLoader.load(ConfigParser.class)) .forEach(parser -> { supportedMediaTypes.addAll(parser.supportedMediaTypes()); supportedSuffixes.addAll(parser.supportedSuffixes()); }); SUPPORTED_MEDIA_TYPES = Set.copyOf(supportedMediaTypes); SUPPORTED_SUFFIXES = List.copyOf(supportedSuffixes); } private final Config metaConfig; MetaConfig() { this.metaConfig = metaConfig().orElseGet(Config::empty); } /** * Create configuration from meta configuration (files or classpath resources), or create a default config instance * if meta configuration is not present. * * @return a config instance */ public static Config config() { return metaConfig().map(MetaConfig::config) // if not found, create a default instance .orElseGet(MetaConfig::createDefault); } /** * Create configuration from provided meta configuration. * * @param metaConfig meta configuration * @return a new config instance built from meta configuration */ public static Config config(Config metaConfig) { return Config.builder() .config(metaConfig) .build(); } /** * Find meta configuration (files or classpath resources) and create a meta configuration instance from it. * * @return meta configuration if present, or empty */ public static Optional metaConfig() { return MetaConfigFinder.findMetaConfig(SUPPORTED_MEDIA_TYPES::contains, SUPPORTED_SUFFIXES); } /** * Load a polling strategy based on its meta configuration. * * @param metaConfig meta configuration of a polling strategy * @return a polling strategy instance */ public static PollingStrategy pollingStrategy(Config metaConfig) { return MetaProviders.pollingStrategy(metaConfig.get("type").asString().get(), metaConfig.get("properties")); } /** * Load a change watcher based on its meta configuration. * * @param metaConfig meta configuration of a change watcher * @return a change watcher instance */ public static ChangeWatcher changeWatcher(Config metaConfig) { String type = metaConfig.get("type").asString().get(); ChangeWatcher changeWatcher = MetaProviders.changeWatcher(type, metaConfig.get("properties")); if (LOGGER.isLoggable(Level.TRACE)) { LOGGER.log(Level.TRACE, "Loaded change watcher of type \"" + type + "\", class: " + changeWatcher.getClass().getName()); } return changeWatcher; } /** * Load a retry policy based on its meta configuration. * * @param metaConfig meta configuration of retry policy * @return retry policy instance */ public static RetryPolicy retryPolicy(Config metaConfig) { String type = metaConfig.get("type").asString().get(); RetryPolicy retryPolicy = MetaProviders.retryPolicy(type, metaConfig.get("properties")); if (LOGGER.isLoggable(Level.TRACE)) { LOGGER.log(Level.TRACE, "Loaded retry policy of type \"" + type + "\", class: " + retryPolicy.getClass().getName()); } return retryPolicy; } /** * Load a config source (or config sources) based on its meta configuration. * The metaConfig must contain a key {@code type} that defines the type of the source to be found via providers, and * a key {@code properties} with configuration of the config sources * @param sourceMetaConfig meta configuration of a config source * @return config source instance * @see Config.Builder#config(Config) */ public static List configSource(Config sourceMetaConfig) { String type = sourceMetaConfig.get("type").asString().get(); boolean multiSource = sourceMetaConfig.get("multi-source").asBoolean().orElse(false); Config sourceProperties = sourceMetaConfig.get("properties"); if (multiSource) { List sources = MetaProviders.configSources(type, sourceProperties); if (LOGGER.isLoggable(Level.TRACE)) { LOGGER.log(Level.TRACE, "Loaded sources of type \"" + type + "\", values: " + sources); } return sources; } else { ConfigSource source = MetaProviders.configSource(type, sourceProperties); if (LOGGER.isLoggable(Level.TRACE)) { LOGGER.log(Level.TRACE, "Loaded source of type \"" + type + "\", class: " + source.getClass().getName()); } return List.of(source); } } /** * Meta configuration if provided, or empty config if not. * * @return meta configuration */ public Config metaConfiguration() { return this.metaConfig; } // override config source static OverrideSource overrideSource(Config sourceMetaConfig) { String type = sourceMetaConfig.get("type").asString().get(); OverrideSource source = MetaProviders.overrideSource(type, sourceMetaConfig.get("properties")); if (LOGGER.isLoggable(Level.TRACE)) { LOGGER.log(Level.TRACE, "Loaded override source of type \"" + type + "\", class: " + source.getClass().getName()); } return source; } static List configSources(Config metaConfig) { List configSources = new LinkedList<>(); metaConfig.get("sources") .asNodeList() .ifPresent(list -> list.forEach(it -> configSources.addAll(MetaConfig.configSource(it)))); return configSources; } // only interested in config source static List configSources(Function supportedMediaType, List supportedSuffixes) { Optional metaConfigOpt = metaConfig(); return metaConfigOpt .map(MetaConfig::configSources) .orElseGet(() -> MetaConfigFinder.findConfigSource(supportedMediaType, supportedSuffixes) .map(List::of) .orElseGet(List::of)); } private static Config createDefault() { // use defaults Config.Builder builder = Config.builder(); MetaConfigFinder.findConfigSource(SUPPORTED_MEDIA_TYPES::contains, SUPPORTED_SUFFIXES).ifPresent(builder::addSource); return builder.build(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy