AbstractRuleParametersFactory.java

package org.thewonderlemming.c4plantuml.mojo.linting.rules.builtin;

import java.util.AbstractMap.SimpleEntry;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import org.thewonderlemming.c4plantuml.linter.rules.AbstractLintingRule;
import org.thewonderlemming.c4plantuml.linter.rules.RuleParameters;
import org.thewonderlemming.c4plantuml.mojo.linting.BuiltInRules;

/**
 * A base implementation of a factory pattern to build {@link RuleParameters} for any {@link AbstractLintingRule}.
 *
 * @author thewonderlemming
 *
 * <P> the type of POJO embedded within the {@link BuiltInRules} object to configure the current rule.
 */
public abstract class AbstractRuleParametersFactory<P> {

    private final boolean isActivated;

    private final RuleParameters ruleParameters;


    private static Entry<String, String> toStringStringEntry(final Entry<String, Optional<String>> entry) {

        assert (entry.getValue().isPresent()) : "Expected value to be non empty";

        final String value = entry.getValue().isPresent() ? entry.getValue().get() : "";
        return new SimpleEntry<>(entry.getKey(), value);
    }

    /**
     * Default constructor.
     *
     * @param mojoParameters the PJO containing the configuration from the {@code pom.xml} file.
     */
    protected AbstractRuleParametersFactory(final BuiltInRules mojoParameters) {

        final P pojoParameters = getPojoFromBuiltInRules(mojoParameters);
        this.isActivated = getActivatedParameter(pojoParameters);
        this.ruleParameters = buildRuleParameters(pojoParameters);
    }

    /**
     * Returns the built {@link RuleParameters} instance.
     *
     * @return the  built {@link RuleParameters}.
     */
    public RuleParameters getRuleParameters() {
        return this.ruleParameters;
    }

    /**
     * Tells whether or not the current {@link AbstractLintingRule} is enabled or disabled.
     *
     * @return {@code true} is the rule is enabled, {@code false} else.
     */
    public boolean isActivated() {
        return this.isActivated;
    }

    /**
     * Extracts and returns the value of the {@code isActivated} parameter from a POJO in the {@link BuiltInRules} POJO.
     *
     * @param pojoParameters the POJO that holds the {@code pom.xml} plugin configuration.
     * @return the value of the {@code isActivated} parameter.
     */
    protected abstract boolean getActivatedParameter(final P pojoParameters);

    /**
     * Retrieves the rule configuration POJO from the {@link BuiltInRules} POJO.
     *
     * @param mojoParameters the POJO that hosts the rule configuration object.
     * @return the rule configuration object.
     */
    protected abstract P getPojoFromBuiltInRules(final BuiltInRules mojoParameters);

    /**
     * Returns the parameters names for the current {@link AbstractLintingRule}.
     *
     * @return the parameters names for the rule.
     */
    protected abstract Set<String> getRuleParametersKeys();

    /**
     * Extracts and returns the value of the given parameter {@code key} from a POJO in the {@link BuiltInRules} POJO.
     *
     * @param key the name of the parameter to retrieves the value from.
     * @param pojoParameters the POJO that holds the {@code pom.xml} plugin configuration.
     * @return the value of the {@code key} parameter.
     */
    protected abstract Optional<String> getValueForParameter(final String key, final P pojoParameters);

    private RuleParameters buildRuleParameters(final P pojoParameters) {

        final Set<String> parametersKeys = getRuleParametersKeys();

        return RuleParameters
            .builder()
                .addParameters(parametersKeys
                    .stream()
                        .map(key -> keyToKeyValuePair(key, pojoParameters))
                        .filter(entry -> entry.getValue().isPresent())
                        .map(AbstractRuleParametersFactory::toStringStringEntry)
                        .collect(Collectors.toMap(Entry::getKey, Entry::getValue)))
                .build();
    }

    private Entry<String, Optional<String>> keyToKeyValuePair(final String key, final P pojoParameters) {
        return new SimpleEntry<>(key, getValueForParameter(key, pojoParameters));
    }
}