class KeyValueConfigSource implements ConfigSource {

  @Override
  public Map<String, ConfigProperty> loadConfig() {
    List<CompletableFuture<List<KeyValueConfigEntity>>> futureList =
        configNames.stream().map(this::loadConfig).collect(Collectors.toList());

    CompletableFuture<Void> allResults =
        CompletableFuture.allOf(futureList.toArray(new CompletableFuture[futureList.size()]));

    CompletableFuture<List<List<KeyValueConfigEntity>>> joinedFuture =
        allResults.thenApply(
            input -> futureList.stream().map(CompletableFuture::join).collect(Collectors.toList()));

    List<List<KeyValueConfigEntity>> resultList;
    try {
      resultList = joinedFuture.get(repositoryTimeout.toMillis(), TimeUnit.MILLISECONDS);
    } catch (ExecutionException e) {
      throw ThrowableUtil.propagate(e.getCause());
    } catch (TimeoutException e) {
      String message =
          String.format("TimeoutException after '%s' millis", repositoryTimeout.toMillis());
      throw new ConfigSourceNotAvailableException(message, e);
    } catch (InterruptedException e) {
      Thread.interrupted();
      throw ThrowableUtil.propagate(e);
    }

    return resultList
        .stream()
        .flatMap(Collection::stream)
        .filter(i -> !i.getDisabled())
        .collect(
            Collector.of(
                (Supplier<TreeMap<String, ConfigProperty>>) TreeMap::new,
                (map, i) -> {
                  String origin = i.getConfigName().getQualifiedName();
                  String name = i.getPropName();
                  String value = i.getPropValue();
                  map.putIfAbsent(
                      name,
                      LoadedConfigProperty.withNameAndValue(name, value).origin(origin).build());
                },
                (map1, map2) -> map1));
  }

  private  KeyValueConfigSource(Builder builder);

}