class ExpectAces implements ProgressCheckFactory {

    static List<AceCriteria> parseAceCriteria(final @NotNull JsonObject config,
                                              final @NotNull String[] principals,
                                              final @NotNull String key) throws Exception {
        final List<AceCriteria> allCriterias = new ArrayList<>();
        final List<String> specs = JavaxJson.mapArrayOfStrings(JavaxJson.arrayOrEmpty(config, key));
        final List<String> generalSpecs = specs.stream().filter(ExpectAces::isGeneralSpec).collect(Collectors.toList());
        if (!generalSpecs.isEmpty() && principals.length == 0) {
            throw new Exception("principal or principals check config param must be non-empty if general ACE criteria are specified");
        } else {
            for (String principal : principals) {
                final Result<List<AceCriteria>> expectedAceResults = generalSpecs.stream()
                        .map(spec -> AceCriteria.parse(principal, spec))
                        .collect(Result.tryCollect(Collectors.toList()));
                if (expectedAceResults.getError().isPresent()) {
                    throw new Exception("invalid criteria in " + key + ". " + expectedAceResults.getError()
                            .map(Throwable::getMessage).orElse(""));
                }
                expectedAceResults.forEach(allCriterias::addAll);
            }
        }
        final Result<List<AceCriteria>> principalAceResults = specs.stream()
                .filter(ExpectAces::isPrincipalSpec)
                .map(spec -> AceCriteria.parse("", spec))
                .collect(Result.tryCollect(Collectors.toList()));
        if (principalAceResults.getError().isPresent()) {
            throw new Exception("invalid criteria in " + key + ". " + principalAceResults.getError()
                    .map(Throwable::getMessage).orElse(""));
        }
        principalAceResults.forEach(allCriterias::addAll);

        return allCriterias;
    }

}