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

cdc.applic.dictionaries.impl.SectionStructureImpl Maven / Gradle / Ivy

The newest version!
package cdc.applic.dictionaries.impl;

import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.stream.Collectors;

import cdc.applic.dictionaries.Dictionary;
import cdc.applic.dictionaries.Registry;
import cdc.applic.expressions.literals.SName;
import cdc.graphs.core.GraphPath;
import cdc.graphs.core.SlimGraph;
import cdc.util.debug.Printables;
import cdc.util.debug.Verbosity;
import cdc.util.lang.Checks;
import cdc.util.paths.Path;

public class SectionStructureImpl implements SectionStructure {
    private static final String PATH = "path";

    private final RepositoryImpl repository;
    /** The associated dictionary. */
    private final AbstractDictionaryImpl dictionary;
    /** The parent when it is unique (policy). */
    private final AbstractDictionaryImpl parent;
    /** All parents, even when it is unique */
    private final List parents = new ArrayList<>();
    /** Sorted ancestors, from itself to farthest ancestors. */
    private final List ancestors = new ArrayList<>();
    /** Sorted descendants, from itself to farthest descendants. */
    private final List descendants = new ArrayList<>();
    /** Paths from all ancestors to this dictionary. */
    private final List> pathsFromAncestors = new ArrayList<>();
    /** Name of the dictionary. */
    private final String name;
    private final SName prefix;
    /** Path of the dictionary. */
    private final Path path;
    /** Description of the dictionary. */
    private final DescriptionImpl description = new DescriptionImpl();
    /** List of children dictionaries. */
    protected final List children = new ArrayList<>();

    SectionStructureImpl(RepositoryImpl repository,
                         AbstractDictionaryImpl dictionary,
                         String name,
                         SName prefix,
                         AbstractDictionaryImpl parent,
                         List parents) {
        Checks.isTrue(Path.isValidName(name), "Invalid dictionary name " + name);
        Checks.isNotNull(parents, "parents");

        this.repository = Checks.isNotNull(repository, "repository");
        this.dictionary = Checks.isNotNull(dictionary, "dictionary");
        this.parent = parent;
        this.name = name;
        this.prefix = prefix;
        if (parent == null) {
            this.path = new Path(Path.SLASH + name);
        } else {
            this.path = new Path(parent.structure.path.toString() + Path.SLASH + name);
        }

        this.parents.addAll(parents);
        for (final AbstractDictionaryImpl p : parents) {
            p.structure.children.add(dictionary);
        }
    }

    void build() {
        // First compute ancestors
        ancestors.addAll(SlimGraph.topologicalSort(dictionary,
                                                   x -> x.structure.parents));
        Checks.assertTrue(!ancestors.isEmpty() && ancestors.get(0) == dictionary, "Implementation error");

        // Then update descendants of all ancestors
        // Note: is this useful? At the time of creation of a dictionary, it does not have any descendants.
        for (final AbstractDictionaryImpl ancestor : ancestors) {
            ancestor.structure.updateDescendants();
        }

        // Compute paths from ancestors.
        for (final AbstractDictionaryImpl p : parents) {
            // 1) Take paths of parents and add this dictionary
            for (final GraphPath parentPath : p.structure.pathsFromAncestors) {
                final GraphPath newPath = GraphPath.builder(AbstractDictionaryImpl.class)
                                                                           .push(parentPath)
                                                                           .push(dictionary)
                                                                           .build();
                pathsFromAncestors.add(newPath);
            }

            // 2) take parents and add this dictionary.
            final GraphPath newPath = GraphPath.builder(AbstractDictionaryImpl.class)
                                                                       .push(p, dictionary)
                                                                       .build();
            pathsFromAncestors.add(newPath);
        }
    }

    private final void updateDescendants() {
        descendants.clear();
        descendants.addAll(SlimGraph.topologicalSort(dictionary,
                                                     x -> x.structure.children));
        Checks.assertTrue(!descendants.isEmpty() && descendants.get(0) == dictionary, "Implementation error");
    }

    void setParents(List parents) {
        Checks.assertTrue(this.parent == null, "Setting parents of a policy.");
        Checks.assertTrue(this.parents.isEmpty(), "Setting parents too late (already attached to parents).");
        Checks.assertTrue(this.children.isEmpty(), "Setting parents too late (already has children).");

        this.ancestors.clear();
        this.pathsFromAncestors.clear();

        this.parents.addAll(parents);
        for (final AbstractDictionaryImpl p : parents) {
            p.structure.children.add(dictionary);
        }

        build();
    }

    @Override
    public RepositoryImpl getRepository() {
        return repository;
    }

    public AbstractDictionaryImpl getParent() {
        return parent;
    }

    @Override
    public List getParents() {
        return parents;
    }

    @Override
    public  List getParents(Class cls) {
        return parents.stream()
                      .filter(cls::isInstance)
                      .map(cls::cast)
                      .toList();
    }

    @Override
    public List getSortedAncestors(boolean self) {
        if (self) {
            return ancestors;
        } else {
            return ancestors.subList(1, ancestors.size());
        }
    }

    /**
     * Explores all paths that start on a specific ancestor and reach this dictionary.
     *
     * @param ancestor The ancestor.
     * @param consumer The path consumer.
     */
    void explorePathsFromAncestor(AbstractDictionaryImpl ancestor,
                                  Consumer> consumer) {
        for (final GraphPath p : pathsFromAncestors) {
            if (p.getItems().get(0) == ancestor) {
                consumer.accept(p);
            }
        }
    }

    /**
     * Explores all paths that start on a root dictionary and reach this dictionary.
     *
     * @param consumer The path consumer.
     */
    void explorePathsFromRoots(Consumer> consumer) {
        for (final GraphPath p : pathsFromAncestors) {
            if (!p.getItems().get(0).hasParents()) {
                consumer.accept(p);
            }
        }
    }

    @Override
    public List getSortedDescendants(boolean self) {
        if (self) {
            return descendants;
        } else {
            return descendants.subList(1, descendants.size());
        }
    }

    @Override
    public DescriptionImpl getDescription() {
        return description;
    }

    @Override
    public String getDesignation() {
        return (dictionary instanceof Registry ? "Registry " : "Policy ") + getPath();
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public Optional getPrefix() {
        return Optional.ofNullable(prefix);
    }

    @Override
    public boolean isDeclaredPrefix(SName prefix) {
        if (prefix == null) {
            return false;
        } else {
            // WARNING: we do a linear search
            // Would be faster with a set, but practically may be sufficient
            for (final AbstractDictionaryImpl ancestor : getRegistry().getSortedAncestors(true)) {
                if (prefix.equals(ancestor.getPrefix().orElse(null))) {
                    return true;
                }
            }
            return false;
        }
    }

    @Override
    public Path getPath() {
        return path;
    }

    @Override
    public RegistryImpl getRegistry() {
        return dictionary instanceof final RegistryImpl x
                ? x
                : getParent().getRegistry();
    }

    @Override
    public  D getDictionary(Path path,
                                                  Class cls) {
        Checks.isNotNull(path, PATH);
        Checks.isNotNull(cls, "cls");

        final Path p;
        if (path.isAbsolute()) {
            p = path;
        } else {
            p = new Path(getPath().toString() + Path.SLASH + path).normalize();
        }
        return getRepository().getDictionary(p, cls);
    }

    @Override
    public  D getDictionary(String path,
                                                  Class cls) {
        return getDictionary(Path.of(path), cls);
    }

    @Override
    public AbstractDictionaryImpl getDictionary(Path path) {
        return getDictionary(path, AbstractDictionaryImpl.class);
    }

    @Override
    public AbstractDictionaryImpl getDictionary(String path) {
        Checks.isNotNull(path, PATH);

        return getDictionary(Path.of(path));
    }

    @Override
    public RegistryImpl getRegistry(Path path) {
        return getDictionary(path, RegistryImpl.class);
    }

    @Override
    public RegistryImpl getRegistry(String path) {
        Checks.isNotNull(path, PATH);

        return getRegistry(Path.of(path));
    }

    @Override
    public PolicyImpl getPolicy(Path path) {
        return getDictionary(path, PolicyImpl.class);
    }

    @Override
    public PolicyImpl getPolicy(String path) {
        Checks.isNotNull(path, PATH);

        return getPolicy(new Path(path));
    }

    @Override
    public List getChildren() {
        return children;
    }

    @Override
    public  List getChildren(Class cls) {
        return children.stream()
                       .filter(cls::isInstance)
                       .map(cls::cast)
                       .toList();
    }

    @Override
    public PolicyImpl.Builder policy() {
        return PolicyImpl.builder(dictionary);
    }

    @Override
    public void printLocalStructure(PrintStream out,
                                    int level,
                                    Verbosity verbosity) {
        final String k = dictionary instanceof RegistryImpl ? "Registry" : "Policy";
        Printables.indent(out, level);
        out.println(k + " '" + getName() + "'");
        Printables.indent(out, level + 1);
        out.println("Caches serial: " + dictionary.getCachesSerial());
        Printables.indent(out, level + 1);
        out.println("Prefix: " + getPrefix());
        Printables.indent(out, level + 1);
        out.println("Context: " + dictionary.getContextExpression());

        Printables.indent(out, level + 1);
        out.println("Parents (" + getParents().size() + ")");
        for (final Dictionary p : getParents()) {
            Printables.indent(out, level + 2);
            out.println("'" + p.getName() + "'");
        }

        Printables.indent(out, level + 1);
        out.println("Sorted Ancestors : "
                + getSortedAncestors(false).stream()
                                           .map(x -> x.getPath().toString())
                                           .collect(Collectors.joining(", ", "[", "]")));
        Printables.indent(out, level + 1);
        out.println("Sorted Descendants : "
                + getSortedDescendants(false).stream()
                                             .map(x -> x.getPath().toString())
                                             .collect(Collectors.joining(", ", "[", "]")));

        Printables.indent(out, level + 1);
        out.println("Paths from ancestors (" + pathsFromAncestors.size() + ")");
        for (final GraphPath p : pathsFromAncestors) {
            Printables.indent(out, level + 2);
            out.println(p);
        }

    }

    @Override
    public void printChildrenPolicies(PrintStream out,
                                      int level,
                                      Verbosity verbosity) {
        Printables.indent(out, level);
        out.println("Policies (" + getChildren(PolicyImpl.class).size() + ")");
        for (final PolicyImpl policy : getChildren(PolicyImpl.class)) {
            policy.print(out, level + 1, verbosity);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy