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

es.iti.wakamiti.api.imconfig.internal.ApacheConfiguration2 Maven / Gradle / Ivy

The newest version!
/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 */
package es.iti.wakamiti.api.imconfig.internal;


import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.type.TypeFactory;
import es.iti.wakamiti.api.imconfig.Configuration;
import es.iti.wakamiti.api.imconfig.ConfigurationFactory;
import es.iti.wakamiti.api.imconfig.PropertyDefinition;
import org.apache.commons.configuration2.BaseConfiguration;
import org.apache.commons.configuration2.convert.DefaultListDelimiterHandler;

import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;


public class ApacheConfiguration2 extends AbstractConfiguration {

    protected final org.apache.commons.configuration2.Configuration conf;
    private final Map, BiFunction> CONVERTER = Map.of(
            List.class, (key, ct) -> getList(key, rawTypes(ct, 1)[0]),
            Set.class, (key, ct) -> getSet(key, rawTypes(ct, 1)[0]),
            Stream.class, (key, ct) -> getStream(key, rawTypes(ct, 1)[0]),
            Map.class, (key, ct) -> {
                Class[] types = rawTypes(ct, 2);
                return inner(key).asMap().entrySet().stream()
                        .collect(Collectors.toMap(
                                e -> convert(e.getKey(), types[0]),
                                e -> convert(e.getValue(), types[1]))
                        );
            }
    );

    protected ApacheConfiguration2(
            ConfigurationFactory builder,
            Map definitions,
            org.apache.commons.configuration2.Configuration conf
    ) {
        super(builder, definitions);
        this.conf = conf;
    }

    protected ApacheConfiguration2(
            ConfigurationFactory builder,
            org.apache.commons.configuration2.Configuration conf
    ) {
        super(builder, Map.of());
        this.conf = conf;
    }

    @Override
    public Configuration withPrefix(String keyPrefix) {
        BaseConfiguration innerConf = prepare(new BaseConfiguration());
        conf.getKeys().forEachRemaining(key -> innerConf.addProperty(keyPrefix + "." + key, conf.getProperty(key)));
        return new ApacheConfiguration2(builder, definitions, innerConf);
    }

    @Override
    public Configuration filtered(String keyPrefix) {
        BaseConfiguration innerConf = prepare(new BaseConfiguration());
        conf.getKeys(keyPrefix).forEachRemaining(key -> {
            if (key.startsWith(keyPrefix)) {
                innerConf.addProperty(key, conf.getProperty(key));
            }
        });
        return new ApacheConfiguration2(builder, definitions, innerConf);
    }

    @Override
    public Configuration inner(String keyPrefix) {
        if (keyPrefix == null || keyPrefix.isEmpty()) {
            return this;
        }
        return new ApacheConfiguration2(builder, definitions, conf.subset(keyPrefix));
    }

    @Override
    public boolean isEmpty() {
        return conf.isEmpty();
    }

    @Override
    public boolean hasProperty(String key) {
        return conf.containsKey(key);
    }

    @Override
    public Iterable keys() {
        return keyList();
    }

    @Override
    public Iterator keyIterator() {
        return conf.getKeys();
    }

    @Override
    public Stream keyStream() {
        return keyList().stream();
    }

    private List keyList() {
        List keys = new ArrayList<>();
        conf.getKeys().forEachRemaining(keys::add);
        return keys;
    }

    @Override
    public  Optional get(String key, Class type) {
        var definition = definitions.get(key);
        String raw = conf.getString(key);
        boolean empty = (raw == null || raw.isEmpty());
        if (definition != null) {
            var value = empty ? definition.defaultValue().orElse(null) : raw;
            if (value != null) {
                return Optional.of(convert(value, type));
            } else {
                return Optional.empty();
            }
        } else {
            return Optional.ofNullable(empty ? null : conf.get(type, key));
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public  Optional get(String key, TypeReference type) {
        JavaType jt = TypeFactory.defaultInstance().constructType(type.getType());
        JavaType[] containedTypes = IntStream.range(0, jt.containedTypeCount())
                .mapToObj(jt::containedType)
                .toArray(JavaType[]::new);
        return (Optional) Optional.ofNullable(CONVERTER.getOrDefault(jt.getRawClass(),
                        (k, ct) -> get(k, jt.getRawClass()).orElse(null)))
                .map(f -> f.apply(key, containedTypes));
    }

    private Class[] rawTypes(JavaType[] jt, int length) {
        Class[] types = new Class[length];
        for (int i = 0; i < length; i++) {
            try {
                types[i] = jt[i].getRawClass();
            } catch (ArrayIndexOutOfBoundsException e) {
                types[i] = String.class;
            }
        }
        return types;
    }

    @Override
    public  List getList(String key, Class type) {
        return Optional.ofNullable(conf.getList(type, key)).orElse(Collections.emptyList());
    }

    @Override
    public  Set getSet(String key, Class type) {
        return new HashSet<>(getList(key, type));
    }

    @Override
    public  Stream getStream(String key, Class type) {
        return getList(key, type).stream();
    }

    @Override
    public Properties asProperties() {
        Properties properties = new Properties();
        conf.getKeys().forEachRemaining(key -> properties.put(key, conf.getString(key)));
        return properties;
    }

    @Override
    public Map asMap() {
        Map map = new LinkedHashMap<>();
        conf.getKeys().forEachRemaining(key -> map.put(key, conf.getString(key)));
        return map;
    }

    @Override
    public String toString() {
        StringBuilder string = new StringBuilder("configuration:\n---------------\n");
        conf.getKeys().forEachRemaining(key -> {
            final String[] values = conf.getStringArray(key);
            String value = "";
            if (values.length == 1) {
                value = values[0];
            } else if (values.length > 1) {
                value = Arrays.toString(values);
            }
            string
                    .append(key)
                    .append(" : ")
                    .append(value)
                    .append("\n");
        });
        return string.append("---------------").toString();
    }

    @Override
    public void forEach(BiConsumer consumer) {
        conf.getKeys().forEachRemaining(key -> consumer.accept(key, conf.get(String.class, key)));
    }

    private  T convert(String raw, Class type) {
        var abstractConf = (org.apache.commons.configuration2.AbstractConfiguration) conf;
        return abstractConf.getConversionHandler().to(raw, type, abstractConf.getInterpolator());
    }

    private  T prepare(T abstractConfiguration) {
        if (builder.hasMultiValueSeparator()) {
            abstractConfiguration.setListDelimiterHandler(new DefaultListDelimiterHandler(builder.multiValueSeparator()));
        }
        return abstractConfiguration;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy