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

io.honeybadger.reporter.config.PlayConfigContext Maven / Gradle / Ivy

There is a newer version: 2.1.2
Show newest version
package io.honeybadger.reporter.config;

import com.typesafe.config.Config;
import com.typesafe.config.ConfigValue;
import io.honeybadger.util.HBStringUtils;
import org.slf4j.LoggerFactory;
import play.Environment;

import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * {@link ConfigContext} implementation that reads its configuration values from
 * a Play Framework {@link Config} class.
 *
 * @author Elijah Zupancic
 * @since 1.0.11
 */
public class PlayConfigContext extends BaseChainedConfigContext {
    /**
     * {@link Map.Entry} implementation for mapping between Play config objects
     * and generic Map.Entry objects.
     *
     * @param  key type
     * @param  value type
     */
    private static final class ConfigEntry implements Map.Entry {
        private final K key;
        private V val;

        static Map.Entry fromConfigValueEntry(
                final Map.Entry entry) {
            return new ConfigEntry<>(entry.getKey(), entry.getValue().unwrapped());
        }

        ConfigEntry(final K key, final V val) {
            this.key = key;
            this.val = val;
        }

        @Override
        public K getKey() {
            return key;
        }

        @Override
        public V getValue() {
            return val;
        }

        @Override
        public V setValue(final V value) {
            final V oldValue = val;
            this.val = value;
            return oldValue;
        }
    }
    /**
     * Converts a Play Configuration to a Honeybadger {@link ConfigContext}. If
     * null, it will default to a {@link SystemSettingsConfigContext}.
     *
     * @param configuration play configuration to convert
     * @param environment play environment to load values from
     */
    public PlayConfigContext(final Config configuration,
                             final Environment environment) {
        super();

        final String env;

        if (environment == null) {
            env = "UNKNOWN";
        } else if (environment.mode().name() == null || environment.mode().name().isEmpty()) {
            env = "UNKNOWN";
        } else {
            env = environment.mode().name();
        }

        if (configuration != null) {
            final Map unwrapped;

            try (Stream> stream = configuration.entrySet().stream()) {
                unwrapped = stream.map(ConfigEntry::fromConfigValueEntry)
                        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
            }

            Map configMap = flattenNestedMap(unwrapped);
            MapConfigContext mapContext = new MapConfigContext(configMap);
            // Overload environment value because it won't be present in the
            // config map.
            mapContext.put(MapConfigContext.ENVIRONMENT_KEY, env);

            overwriteWithContext(mapContext);
        } else {
            LoggerFactory.getLogger(getClass()).warn(
                    "Null Play configuration. Using defaults and system settings.");
            overwriteWithContext(new SystemSettingsConfigContext());
        }
    }

    /**
     * Flattens a hierarchical map of nested maps into a single map with each
     * nesting delineated by a dot. Assumes a nesting level of zero.
     * @param map nested map
     * @return a flat map
     */
    static Map flattenNestedMap(final Map map) {
        return flattenNestedMap(map, 0);
    }

    /**
     * Flattens a hierarchical map of nested maps into a single map with each
     * nesting delineated by a dot.
     * @param map nested map
     * @param level level of nesting
     * @return a flat map
     */
    static Map flattenNestedMap(final Map map, final long level) {
        if (map.isEmpty()) return Collections.emptyMap();

        Map flat = new HashMap<>();

        for (final Map.Entry entry : map.entrySet()) {
            if (entry.getKey() == null || entry.getKey().isEmpty()) continue;

            if (entry.getValue() instanceof Map) {
                // assume that we have the same underlying generic definition
                @SuppressWarnings("unchecked")
                Map innerMap = (Map) entry.getValue();

                // Don't bother to continue processing if this config section is empty
                if (innerMap.isEmpty()) continue;

                Map subFlat = flattenNestedMap(innerMap, level + 1);

                Iterator> subItr = subFlat.entrySet().iterator();

                while (subItr.hasNext()) {
                    Map.Entry subEntry = subItr.next();
                    String subKey = HBStringUtils.stripTrailingChar(subEntry.getKey(), '.');
                    String key = String.format("%s.%s", entry.getKey(), subKey);
                    flat.put(key, subEntry.getValue());
                }
            } else if (level == 0) {
                String key = HBStringUtils.stripTrailingChar(entry.getKey(), '.');
                flat.put(String.format("%s", key), entry.getValue());
            } else {
                String key = HBStringUtils.stripTrailingChar(entry.getKey(), '.');
                flat.put(String.format("%s.", key), entry.getValue());
            }
        }

        return flat;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy