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

cdc.applic.consistency.core.ConsistencyCheckerImpl Maven / Gradle / Ivy

There is a newer version: 0.13.3
Show newest version
package cdc.applic.consistency.core;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import cdc.applic.consistency.Composition;
import cdc.applic.consistency.ConsistencyChecker;
import cdc.applic.consistency.ConsistencyData;
import cdc.applic.consistency.handlers.ConsistencyHandler;
import cdc.applic.consistency.issues.ConsistencyDataLocation;
import cdc.applic.consistency.issues.ConsistencyIssues;
import cdc.applic.consistency.issues.GlobalIssueType;
import cdc.applic.consistency.issues.NodeIssueType;
import cdc.applic.dictionaries.Dictionary;
import cdc.applic.dictionaries.Registry;
import cdc.applic.dictionaries.checks.WritingRuleChecker;
import cdc.applic.dictionaries.core.checks.DictionaryChecker;
import cdc.applic.dictionaries.handles.DictionaryHandle;
import cdc.applic.expressions.ApplicException;
import cdc.applic.expressions.Expression;
import cdc.applic.expressions.Expressions;
import cdc.applic.expressions.checks.ApplicIssue;
import cdc.applic.expressions.checks.CheckedData;
import cdc.applic.proofs.Prover;
import cdc.applic.proofs.ProverFeatures;
import cdc.applic.proofs.core.clauses.ProverImpl;
import cdc.applic.simplification.Simplifier;
import cdc.applic.simplification.SimplifierFeatures;
import cdc.applic.simplification.core.SimplifierImpl;
import cdc.issues.Diagnosis;
import cdc.issues.Issue;

public class ConsistencyCheckerImpl implements ConsistencyChecker {

    @Override
    public void check(ConsistencyData data,
                      ConsistencyHandler handler) {
        final Executor computer = new Executor<>(data, handler);
        computer.execute();
    }

    @Override
    public List check(ConsistencyData data) {
        final List events = new ArrayList<>();
        final ConsistencyHandler handler = new ConsistencyHandler() {
            @Override
            public void beginAnalysis() {
                // Ignore
            }

            @Override
            public void endAnalysis() {
                // Ignore
            }

            @Override
            public void issue(Issue issue) {
                events.add(issue);
            }
        };
        check(data, handler);
        return events;
    }

    private static class Executor {
        private final ConsistencyData data;
        private final ConsistencyHandler handler;
        /** Set of processed nodes. **/
        private final Set processed = new HashSet<>();
        /** Set of collected policies. */
        private final Set dictionaries = new HashSet<>();
        private final Map actualApplic = new HashMap<>();
        private final Map handles = new HashMap<>();
        private final Map provers = new HashMap<>();
        private final boolean usableData = true;

        // TODO merged dictionary for actual applic

        public Executor(ConsistencyData data,
                        ConsistencyHandler handler) {
            this.data = data;
            this.handler = handler;
        }

        private DictionaryHandle getDictionaryHandle(Dictionary dictionary) {
            return dictionary == null
                    ? null
                    : handles.computeIfAbsent(dictionary, DictionaryHandle::new);
        }

        private DictionaryHandle getLocalHandle(N node) {
            return getDictionaryHandle(data.getNodeDictionary(node));
        }

        private Expression getActualApplic(N node) {
            return actualApplic.get(node);
        }

        private Dictionary getActualDictionary(N node) {
            // TODO MergedDictionary
            return data.getNodeDictionary(node);
        }

        private Prover getProver(Dictionary dictionary) {
            return provers.computeIfAbsent(dictionary,
                                           p -> new ProverImpl(getDictionaryHandle(p),
                                                               ProverFeatures.INCLUDE_ASSERTIONS_ALL_POSSIBLE_RESERVES));
        }

        private B asBlock(N node) {
            @SuppressWarnings("unchecked")
            final B block = (B) node;
            return block;
        }

        private R asReference(N node) {
            @SuppressWarnings("unchecked")
            final R reference = (R) node;
            return reference;
        }

        private String toString(N node,
                                boolean capital,
                                boolean applic) {
            final StringBuilder builder = new StringBuilder();
            builder.append(ConsistencyData.getPath(data, node, capital));
            if (applic) {
                builder.append(" (")
                       .append(data.getNodeLocalApplicability(node))
                       .append(')');
            }
            return builder.toString();
        }

        private static String toString(Expression expression) {
            return expression.getContent();
        }

        /**
         * Collect data before running checks.
         */
        private void prepareData() {
            for (final B root : data.getRootBlocks()) {
                prepareData(root);
            }
            processed.clear();
        }

        /**
         * Collects data related to a Node:
         * 
    *
  • Policies *
  • Actual applicabilities *
* * @param node The node. */ private void prepareData(N node) { processed.add(node); final Dictionary dictionary = data.getNodeDictionary(node); if (dictionary == null) { issue(NodeIssueType.NULL_DICTIONARY, toString(node, true, false) + " dictionary cannot be found.", node); } else { dictionaries.add(dictionary); if (data.isBlock(node)) { computeActualApplic(asBlock(node)); for (final N child : data.getBlockChildren(asBlock(node))) { prepareData(child); if (data.isReference(child)) { computeActualApplic(asBlock(node), asReference(child)); } } } } } private Expression simplify(Expression expression, Dictionary dictionary) { final Simplifier simplifier = new SimplifierImpl(getDictionaryHandle(dictionary)); final SimplifierFeatures features = SimplifierFeatures.builder() .proverFeatures(ProverFeatures.INCLUDE_ASSERTIONS_ALL_POSSIBLE_RESERVES) .allHints() .build(); try { return simplifier.simplify(expression, features).getValue(); } catch (final ApplicException e) { return expression; } } private void computeActualApplic(B block) { if (!actualApplic.containsKey(block)) { final List effectives = new ArrayList<>(); for (final B parent : data.getBlockParents(block)) { computeActualApplic(parent); effectives.add(getActualApplic(parent)); } effectives.add(data.getNodeLocalApplicability(block)); actualApplic.put(block, simplify(Expressions.SHORT_NARROW_NO_SIMPLIFY.and(effectives), data.getNodeDictionary(block))); } } private void computeActualApplic(B parent, R reference) { if (!actualApplic.containsKey(reference)) { final Expression parentActual = actualApplic.get(parent); final Expression local = data.getNodeLocalApplicability(reference); final Expression effective = Expressions.SHORT_NARROW_NO_SIMPLIFY.and(parentActual, local); actualApplic.put(reference, simplify(effective, data.getNodeDictionary(reference))); } } public void execute() { handler.beginAnalysis(); prepareData(); checkPolicies(); if (usableData) { checkNodes(); } handler.endAnalysis(); } private void checkPolicies() { final Set registries = new HashSet<>(); for (final Dictionary dictionary : dictionaries) { final DictionaryChecker checker = new DictionaryChecker(dictionary); final List issues = new ArrayList<>(); checker.check(issues); handler.issues(issues); // for (final ApplicIssue issue : issues) { // fireDictionaryIssue(dictionary, issue.getDescription()); // } registries.add(dictionary.getRegistry()); } if (registries.size() > 1) { issue(GlobalIssueType.REGISTRY_CONSISTENCY, "Policies are not based on the same registry."); } } private void checkNodes() { for (final B root : data.getRootBlocks()) { checkNode(root); } } private void checkNode(N node) { processed.add(node); final boolean localCompliance = checkLocalApplicCompliance(node); if (localCompliance) { // Not necessary to check actual compliance if local compliance is absent checkActualApplicCompliance(node); } if (data.isBlock(node)) { checkBlockComposition(asBlock(node)); for (final N child : data.getBlockChildren(asBlock(node))) { checkNode(child); } } else { checkReference(asReference(node)); } } /** * Checks the compliance of a node applicability restriction with its dictionary. * * @param node The node. * @return {@code true} if compliance is OK. */ private boolean checkLocalApplicCompliance(N node) { final Expression applic = data.getNodeLocalApplicability(node); final DictionaryHandle handle = getLocalHandle(node); if (handle != null) { final Diagnosis diagnosis = WritingRuleChecker.check(handle, new CheckedData(data.getSystemId() + "/" + toString(node, true, true), applic)); handler.issues(diagnosis.getIssues()); return diagnosis.isOk(); } else { return false; } } private void checkActualApplicCompliance(N node) { final Expression applic = getActualApplic(node); final DictionaryHandle handle = getLocalHandle(node); if (handle != null) { final Diagnosis diagnosis = WritingRuleChecker.check(getLocalHandle(node), new CheckedData(data.getSystemId() + "/" + toString(node, true, false), applic)); handler.issues(diagnosis.getIssues()); } } private void checkNonEmptyIntersection(B parent, N child) { final Expression parentApplic = getActualApplic(parent); final Expression childApplic = getActualApplic(child); final Prover prover = getProver(getActualDictionary(child)); final boolean success = prover.intersects(parentApplic, childApplic); if (!success) { issue(NodeIssueType.ACTUAL_CHILD_PARENT_COMPLIANCE, toString(child, true, true) + " is never applicable in its parent." + toString(parent, false, true) + ".", child); } } private void checkBlockComposition(B block) { final Composition composition = data.getBlockComposition(block); if (composition != Composition.ANY) { final List childrenBlocks = new ArrayList<>(); final List childrenApplic = new ArrayList<>(); for (final N child : data.getBlockChildren(block)) { if (data.isBlock(child)) { childrenBlocks.add(asBlock(child)); childrenApplic.add(getActualApplic(child)); } } if (childrenBlocks.isEmpty()) { if (composition == Composition.AT_LEAST_ONE) { issue(NodeIssueType.AT_LEAST_ONE_COMPLIANCE, toString(block, true, true) + " has no applicable children.", block); } else if (composition == Composition.EXACTLY_ONE) { issue(NodeIssueType.EXACTLY_ONE_COMPLIANCE, toString(block, true, true) + " has no applicable children.", block); } } else { final Expression context = getActualApplic(block); final Expression[] expressions = childrenApplic.toArray(new Expression[childrenApplic.size()]); final Prover prover = getProver(getActualDictionary(block)); if (composition == Composition.AT_LEAST_ONE) { final boolean success = prover.alwaysAtLeastOneInContext(context, expressions); if (!success) { issue(NodeIssueType.AT_LEAST_ONE_COMPLIANCE, toString(block, true, true) + " does not have at least one applicable child.", block); } } else if (composition == Composition.EXACTLY_ONE) { final boolean success = prover.alwaysExactlyOneInContext(context, expressions); if (!success) { issue(NodeIssueType.EXACTLY_ONE_COMPLIANCE, toString(block, true, true) + " does not have exactly one applicable child.", block); } } else { final boolean success = prover.alwaysAtMostOneInContext(context, expressions); if (!success) { issue(NodeIssueType.AT_MOST_ONE_COMPLIANCE, toString(block, true, true) + " does not have at most one applicable child.", block); } } } } for (final N child : data.getBlockChildren(block)) { checkNonEmptyIntersection(block, child); } } private void checkReference(R ref) { final B target = data.getReferenceTarget(ref); if (target == null) { issue(NodeIssueType.NULL_TARGET, toString(ref, true, false) + " target cannot be found.", ref); } else { final Prover prover = getProver(getActualDictionary(ref)); final Expression inner = getActualApplic(ref); final Expression outer = getActualApplic(target); final boolean included = prover.contains(outer, inner); if (!included) { issue(NodeIssueType.ACTUAL_REF_TARGET_COMPLIANCE, "Actual applic of " + toString(ref, false, false) + " (" + toString(inner) + ") is not included in actual applic of its target " + toString(target, false, false) + " (" + toString(outer) + ").", ref); } } } private void issue(GlobalIssueType type, String description) { handler.issue(ConsistencyIssues.builder() .name(type) .description(description) .addLocation(new ConsistencyDataLocation(data)) .build()); } private void issue(NodeIssueType type, String description, N node) { handler.issue(ConsistencyIssues.builder() .name(type) .description(description) .addLocation(new ConsistencyDataLocation(data, node)) .build()); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy