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

ratpack.config.internal.source.EnvironmentConfigSource Maven / Gradle / Ivy

There is a newer version: 2.0.0-rc-1
Show newest version
/*
 * 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.ConfigDataBuilder;
import ratpack.config.ConfigSource;
import ratpack.config.EnvironmentParser;
import ratpack.file.FileSystemBinding;
import ratpack.func.Function;
import ratpack.func.Pair;
import ratpack.func.Predicate;
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 DEFAULT_MAP_FUNC = camelCase();

  private final ServerEnvironment serverEnvironment;
  private final EnvironmentParser parser;

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

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

  public EnvironmentConfigSource(ServerEnvironment serverEnvironment, String prefix, Function 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, FileSystemBinding fileSystemBinding) 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 mapPathSegments(Pair, String> entry) {
    return entry.getLeft().stream().map(getMapFunc()).collect(Collectors.toList());
  }

  private void populate(ObjectNode node, List 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, Stream>> getFilterFunc() {
    return ((Function, Stream>>) parser::filter).toFunction();
  }

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

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

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

  public static Function, Stream>> 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> splitObjects(String objectDelimiter) {
    return Splitter.on(objectDelimiter)::splitToList;
  }

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

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

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




© 2015 - 2025 Weber Informatics LLC | Privacy Policy