private CompletionStage<AuthorizationStatus> authorizeAndSupplyHandlers(
            Iterator<? extends Authorizer<T>> iterator,
            boolean first, @Nullable AuthFailureHandler prevFailureHandler,
            ServiceRequestContext ctx, @Nullable T data) {
        final Authorizer<T> nextAuthorizer = iterator.next();
        return AuthorizerUtil.authorizeAndSupplyHandlers(nextAuthorizer, ctx, data).thenComposeAsync(result -> {
            if (result == null) {
                throw AuthorizerUtil.newNullResultException(nextAuthorizer);
            } else {
                if (result.isAuthorized()) {
                    // always return associated successHandler on success!
                    // this could be NULL
                    return UnmodifiableFuture.completedFuture(
                            AuthorizationStatus.ofSuccess(result.successHandler()));
                }
                // handle failure result
                final AuthFailureHandler failureHandler;
                final AuthFailureHandler nextFailureHandler = result.failureHandler();
                switch (selectionStrategy) {
                    case FIRST:
                        // (re-)assign the handler only for the FIRST element in the chain
                        if (first) {
                            failureHandler = nextFailureHandler;
                        } else { // passthrough the handler form the previous item
                            failureHandler = prevFailureHandler;
                        }
                        break;
                    case FIRST_WITH_HANDLER:
                        // set failureHandler only if it's not yet set
                        if (prevFailureHandler == null && nextFailureHandler != null) {
                            failureHandler = nextFailureHandler;
                        } else { // passthrough the handler form the previous item
                            failureHandler = prevFailureHandler;
                        }
                        break;
                    case LAST_WITH_HANDLER:
                        // reset failureHandler on any failure
                        if (nextFailureHandler != null) {
                            failureHandler = nextFailureHandler;
                        } else { // passthrough the handler form the previous item
                            failureHandler = prevFailureHandler;
                        }
                        break;
                    default:
                        // passthrough the handler form the previous item
                        failureHandler = prevFailureHandler;
                        break;
                }
                if (!iterator.hasNext()) {
                    // this is the last item in the chain
                    return UnmodifiableFuture.completedFuture(
                            AuthorizationStatus.ofFailure(
                                    (selectionStrategy == AuthorizerSelectionStrategy.LAST) ? nextFailureHandler
                                                                                            : failureHandler));
                }
                // continue to the next...
                return authorizeAndSupplyHandlers(iterator, false, failureHandler, ctx, data);
            }
        }, ctx.eventLoop());
    }
Triggers an authorization on the chain of {@link Authorizer}s.
@return a {@link CompletionStage} that will resolve to {@code true} if any of {@link Authorizer}s in the
        chain authorize the request, or {@code false} if none of {@link Authorizer}s in the chain
        authorize the request. If the future resolves exceptionally, the request will not be authorized.
core/src/main/java/com/linecorp/armeria/server/auth/AuthorizerChain.java