ratpack.config.internal.source.EnvironmentConfigSource.java Source code

Java tutorial

Introduction

Here is the source code for ratpack.config.internal.source.EnvironmentConfigSource.java

Source

/*
 * Copyright 2015 the original author or authors.
 *
 * 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 ratpack.config.internal.source;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.TextNode;
import com.google.common.base.CaseFormat;
import com.google.common.base.Preconditions;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import ratpack.config.ConfigSource;
import ratpack.config.EnvironmentParser;
import ratpack.func.Function;
import ratpack.func.Pair;
import ratpack.func.Predicate;
import ratpack.server.ServerConfig;
import ratpack.server.internal.ServerEnvironment;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class EnvironmentConfigSource implements ConfigSource {
    public static final String DEFAULT_OBJECT_DELIMITER = "__";
    public static final Function<String, String> DEFAULT_MAP_FUNC = camelCase();

    private final ServerEnvironment serverEnvironment;
    private final EnvironmentParser parser;

    public EnvironmentConfigSource(ServerEnvironment serverEnvironment) {
        this(serverEnvironment, ServerConfig.Builder.DEFAULT_ENV_PREFIX);
    }

    public EnvironmentConfigSource(ServerEnvironment serverEnvironment, String prefix) {
        this(serverEnvironment, prefix, DEFAULT_MAP_FUNC);
    }

    public EnvironmentConfigSource(ServerEnvironment serverEnvironment, String prefix,
            Function<String, String> mapFunc) {
        this(serverEnvironment,
                new DefaultEnvironmentParser(filterAndRemoveKeyPrefix(Preconditions.checkNotNull(prefix)),
                        splitObjects(DEFAULT_OBJECT_DELIMITER), mapFunc));
    }

    public EnvironmentConfigSource(ServerEnvironment serverEnvironment, EnvironmentParser parser) {
        this.serverEnvironment = serverEnvironment;
        this.parser = parser;
    }

    @Override
    public ObjectNode loadConfigData(ObjectMapper objectMapper) throws Exception {
        ObjectNode rootNode = objectMapper.createObjectNode();
        serverEnvironment.getenv().entrySet().stream().map(toPair()).flatMap(getFilterFunc())
                .map(getPairTokenizerFunc()).forEach(entry -> {
                    populate(rootNode, mapPathSegments(entry), 0, entry.getRight());
                });
        return rootNode;
    }

    private List<String> mapPathSegments(Pair<List<String>, String> entry) {
        return entry.getLeft().stream().map(getMapFunc()).collect(Collectors.toList());
    }

    private void populate(ObjectNode node, List<String> path, int pathIndex, String value) {
        String segment = path.get(pathIndex);
        if (pathIndex == path.size() - 1) {
            node.set(segment, TextNode.valueOf(value));
        } else {
            // For environment variables, we don't support array indexing.
            // Thus, if there are remaining segments, it must mean that the parent is an object.
            ObjectNode childNode = (ObjectNode) node.get(segment);
            if (childNode == null) {
                childNode = node.putObject(segment);
            }
            populate(childNode, path, pathIndex + 1, value);
        }
    }

    private java.util.function.Function<Pair<String, String>, Stream<Pair<String, String>>> getFilterFunc() {
        return ((Function<Pair<String, String>, Stream<Pair<String, String>>>) parser::filter).toFunction();
    }

    private java.util.function.Function<Pair<String, String>, Pair<List<String>, String>> getPairTokenizerFunc() {
        return ((Function<Pair<String, String>, Pair<List<String>, String>>) e -> e.mapLeft(parser::tokenize))
                .toFunction();
    }

    private java.util.function.Function<String, String> getMapFunc() {
        return ((Function<String, String>) parser::map).toFunction();
    }

    public static Function<String, String> camelCase() {
        return Function.fromGuava(CaseFormat.UPPER_UNDERSCORE.converterTo(CaseFormat.LOWER_CAMEL));
    }

    public static Function<Pair<String, String>, Stream<Pair<String, String>>> filterAndRemoveKeyPrefix(
            String prefix) {
        if (Strings.isNullOrEmpty(prefix)) {
            return Stream::of;
        }
        return entry -> Stream.of(entry).filter(keyStartsWith(prefix).toPredicate())
                .map(removeKeyPrefix(prefix).toFunction());
    }

    public static Function<String, List<String>> splitObjects(String objectDelimiter) {
        return Splitter.on(objectDelimiter)::splitToList;
    }

    private static Predicate<Pair<String, String>> keyStartsWith(String prefix) {
        return entry -> entry.getLeft().startsWith(prefix);
    }

    private static Function<Pair<String, String>, Pair<String, String>> removeKeyPrefix(String prefix) {
        return entry -> entry.mapLeft(key -> key.substring(prefix.length(), key.length()));
    }

    private static java.util.function.Function<Map.Entry<String, String>, Pair<String, String>> toPair() {
        return e -> Pair.of(e.getKey(), e.getValue());
    }
}