liquibase-cdi/src/main/java/liquibase/integration/cdi/SchemesTreeBuilder.java
public List<LiquibaseSchema> build(final String id, Collection<LiquibaseSchema> schemes) {
        log.fine(LogType.LOG, String.format("[id = %s] build(%s)", id, schemes));

        log.info(LogType.LOG, String.format("[id = %s] Sorting schemes according dependencies...", id));

        if (schemes.isEmpty()) {
            return Collections.emptyList();
        }

        SchemaNode root = null;

        // first, copy schemes to no modify source collection
        schemes = new ArrayList<>(schemes);
        Collection<LiquibaseSchema> availableSchemes = new ArrayList<>(schemes);
        // then find not dependent schemes - this will the roots of hierarchy.

        List<LiquibaseSchema> notDependent = new ArrayList<>();
        for (LiquibaseSchema liquibaseSchema : schemes) {
            String depends = liquibaseSchema.depends();
            if (depends.trim().isEmpty()) {
                notDependent.add(liquibaseSchema);
            }
        }

        log.info(LogType.LOG, String.format("[id = %s] Found [%s] not dependent schemes.", id, notDependent.size()));

        if (notDependent.isEmpty()) { // if there is no not-dependent schema, then there is a cyclic dependency.
            throw new CyclicDependencyException(String.format("[id = %s] Not independent schemes, possible cyclic dependencies discovered.", id));
        } else {
            // take first of not-dependent and use it as root of hierarchy.
            root = new SchemaNode(notDependent.get(0));
            log.fine(LogType.LOG, String.format("[id = %s] Selected dependencies tree root [%s]", id, root.getItem()));
            availableSchemes.removeAll(notDependent); // we won't to check not-dependent schemes.
            notDependent.remove(root.getItem());  // remove root from not-dependent schemes
            schemes.retainAll(availableSchemes); // remove not-dependent from all schemes

            // now make all not-dependent schemes children to selected root.
            for (LiquibaseSchema liquibaseSchema : notDependent) {
                root.addChild(liquibaseSchema);
            }

            log.fine(LogType.LOG, String.format("[id = %s] Made other non-dependent schemes children of root. [%s] dependent schemes to resolve. Resolving...",
                    id,
                    availableSchemes.size()
            ));

            int cycles = 0;
            long start = System.currentTimeMillis();
            // until we resolve all dependencies
            while (!availableSchemes.isEmpty()) {
                cycles++;
                log.fine(LogType.LOG, String.format("[id = %s] Resolution cycle [%s] started.", id, cycles));
                int additions = 0; //we will count dependencies resolution for each resolution cycle.
                for (LiquibaseSchema liquibaseSchema : schemes) {
                    log.fine(LogType.LOG, String.format(
                            "[id = %s] LiquibaseSchema [name=%s] depends on liquibaseSchema [name=%s].",
                            id, liquibaseSchema.name(), liquibaseSchema.depends()
                    ));
                    SchemaNode parent = root.find(liquibaseSchema.depends());

                    // we make the dependent liquibaseSchema as a child for it's dependency if found. If not, we just continue.
                    if (parent == null) {
                        log.fine(LogType.LOG, String.format(
                                "[id = %s] Dependency not found in resolved dependencies tree, skipping liquibaseSchema [name=%s] for a while.",
                                id, liquibaseSchema.name()
                        ));

                        boolean isDependencyMissed = true;
                        for (LiquibaseSchema tmpLiquibaseSchema : availableSchemes) {
                            if (tmpLiquibaseSchema.name().equalsIgnoreCase(liquibaseSchema.depends())) {
                                isDependencyMissed = false;
                                break;
                            }
                        }
                        if (isDependencyMissed) {
                            throw new DependencyNotFoundException(String.format(
                                    "[id = %s][name=%s] depends on [name=%s], but it is not found!",
                                    id, liquibaseSchema.name(), liquibaseSchema.depends()
                            ));
                        }
                    } else {
                        log.fine(LogType.LOG, String.format(
                                "[id = %s] Dependency found for liquibaseSchema [name=%s], moving it to resolved dependencies tree.",
                                id, liquibaseSchema.name()
                        ));
                        parent.addChild(liquibaseSchema);
                        availableSchemes.remove(liquibaseSchema);
                        additions++;
                    }
                }
                log.fine(LogType.LOG, String.format("[id = %s] Resolution cycle [%s] completed", id, cycles));

                //if not resolutions happened through resolution cycle, definitely there is a cyclic dependency.
                if (additions == 0) {
                    throw new CyclicDependencyException(String.format("[id = %s] Cyclic dependencies discovered!", id));
                }

                schemes.retainAll(availableSchemes);
            }

            log.info(LogType.LOG, String.format("[id = %s] Dependencies resolved in [cycles=%s, millis=%s]", id, cycles, System.currentTimeMillis() - start));
        }

        return root.toList();
    }
public List<LiquibaseSchema> build(final String id, Collection<LiquibaseSchema> schemes) {
        log.fine(LogType.LOG, String.format("[id = %s] build(%s)", id, schemes));

        log.info(LogType.LOG, String.format("[id = %s] Sorting schemes according dependencies...", id));

        if (schemes.isEmpty()) {
            return Collections.emptyList();
        }

        SchemaNode root = null;

        // first, copy schemes to no modify source collection
        schemes = new ArrayList<>(schemes);
        Collection<LiquibaseSchema> availableSchemes = new ArrayList<>(schemes);
        // then find not dependent schemes - this will the roots of hierarchy.

        List<LiquibaseSchema> notDependent = new ArrayList<>();
        for (LiquibaseSchema liquibaseSchema : schemes) {
            String depends = liquibaseSchema.depends();
            if (depends.trim().isEmpty()) {
                notDependent.add(liquibaseSchema);
            }
        }

        log.info(LogType.LOG, String.format("[id = %s] Found [%s] not dependent schemes.", id, notDependent.size()));

        if (notDependent.isEmpty()) { // if there is no not-dependent schema, then there is a cyclic dependency.
            throw new CyclicDependencyException(String.format("[id = %s] Not independent schemes, possible cyclic dependencies discovered.", id));
        } else {
            // take first of not-dependent and use it as root of hierarchy.
            root = new SchemaNode(notDependent.get(0));
            log.fine(LogType.LOG, String.format("[id = %s] Selected dependencies tree root [%s]", id, root.getItem()));
            availableSchemes.removeAll(notDependent); // we won't to check not-dependent schemes.
            notDependent.remove(root.getItem());  // remove root from not-dependent schemes
            schemes.retainAll(availableSchemes); // remove not-dependent from all schemes

            // now make all not-dependent schemes children to selected root.
            for (LiquibaseSchema liquibaseSchema : notDependent) {
                root.addChild(liquibaseSchema);
            }

            log.fine(LogType.LOG, String.format("[id = %s] Made other non-dependent schemes children of root. [%s] dependent schemes to resolve. Resolving...",
                    id,
                    availableSchemes.size()
            ));

            int cycles = 0;
            long start = System.currentTimeMillis();
            // until we resolve all dependencies
            while (!availableSchemes.isEmpty()) {
                cycles++;
                log.fine(LogType.LOG, String.format("[id = %s] Resolution cycle [%s] started.", id, cycles));
                int additions = 0; //we will count dependencies resolution for each resolution cycle.
                for (LiquibaseSchema liquibaseSchema : schemes) {
                    log.fine(LogType.LOG, String.format(
                            "[id = %s] LiquibaseSchema [name=%s] depends on liquibaseSchema [name=%s].",
                            id, liquibaseSchema.name(), liquibaseSchema.depends()
                    ));
                    SchemaNode parent = root.find(liquibaseSchema.depends());

                    // we make the dependent liquibaseSchema as a child for it's dependency if found. If not, we just continue.
                    if (parent == null) {
                        log.fine(LogType.LOG, String.format(
                                "[id = %s] Dependency not found in resolved dependencies tree, skipping liquibaseSchema [name=%s] for a while.",
                                id, liquibaseSchema.name()
                        ));

                        boolean isDependencyMissed = true;
                        for (LiquibaseSchema tmpLiquibaseSchema : availableSchemes) {
                            if (tmpLiquibaseSchema.name().equalsIgnoreCase(liquibaseSchema.depends())) {
                                isDependencyMissed = false;
                                break;
                            }
                        }
                        if (isDependencyMissed) {
                            throw new DependencyNotFoundException(String.format(
                                    "[id = %s][name=%s] depends on [name=%s], but it is not found!",
                                    id, liquibaseSchema.name(), liquibaseSchema.depends()
                            ));
                        }
                    } else {
                        log.fine(LogType.LOG, String.format(
                                "[id = %s] Dependency found for liquibaseSchema [name=%s], moving it to resolved dependencies tree.",
                                id, liquibaseSchema.name()
                        ));
                        parent.addChild(liquibaseSchema);
                        availableSchemes.remove(liquibaseSchema);
                        additions++;
                    }
                }
                log.fine(LogType.LOG, String.format("[id = %s] Resolution cycle [%s] completed", id, cycles));

                //if not resolutions happened through resolution cycle, definitely there is a cyclic dependency.
                if (additions == 0) {
                    throw new CyclicDependencyException(String.format("[id = %s] Cyclic dependencies discovered!", id));
                }

                schemes.retainAll(availableSchemes);
            }

            log.info(LogType.LOG, String.format("[id = %s] Dependencies resolved in [cycles=%s, millis=%s]", id, cycles, System.currentTimeMillis() - start));
        }

        return root.toList();
    }
Builds a collection of schemes sorted according dependencies

@param schemes All found Liquibase Schema annotations in 'war' or 'ear' type file.
@return sorted collection of schemes