VariantsFactoryFinder.java

package io.github.jonloucks.variants.api;

import java.util.Optional;
import java.util.ServiceLoader;

import static io.github.jonloucks.contracts.api.Checks.configCheck;
import static io.github.jonloucks.contracts.api.Checks.nullCheck;
import static java.util.Optional.ofNullable;

/**
 * Responsible for locating and creating the VariantsFactory for a deployment.
 */
public final class VariantsFactoryFinder {
    
    /**
     * Create a new Variants Factory Finder
     * @param config the Variants configuration
     */
    public VariantsFactoryFinder(Variants.Config config) {
        this.config = configCheck(config);
    }
    
    /**
     * Find a Variants factory
     * @return the optional Variant Factory
     */
    public Optional<VariantsFactory> find() {
        final Optional<VariantsFactory> byReflection = createByReflection();
        return byReflection.isPresent() ? byReflection : createByServiceLoader();
    }
    
    private Optional<VariantsFactory> createByServiceLoader() {
        if (config.useServiceLoader()) {
            try {
                for (VariantsFactory factory : ServiceLoader.load(getServiceFactoryClass())) {
                    return Optional.of(factory);
                }
            } catch (Throwable ignored) {
            }
        }
        return Optional.empty();
    }
    
    private Class<? extends VariantsFactory> getServiceFactoryClass() {
        return nullCheck(config.serviceLoaderClass(), "Variants Service Loader class must be present.");
    }
    
    private Optional<VariantsFactory> createByReflection() {
        if (config.useReflection()) {
            return getReflectionClassName().map(this::createNewInstance);
        }
        return Optional.empty();
    }
    
    private VariantsFactory createNewInstance(String className) {
        try {
            return (VariantsFactory)Class.forName(className).getConstructor().newInstance();
        } catch (Throwable thrown) {
            return null;
        }
    }

    private Optional<String> getReflectionClassName() {
        return ofNullable(config.reflectionClassName()).filter(x -> !x.isEmpty());
    }
    
    private final Variants.Config config;
}