public static <T> T doAndRetry(final List<Class<? extends Throwable>> clazzes,
                                   final RetryCallback<T, Exception> callback,
                                   final int maximumAttempts) throws Exception {
        val retryTemplate = new RetryTemplate();

        val classified = new HashMap<Class<? extends Throwable>, Boolean>();
        classified.put(Error.class, Boolean.TRUE);
        classified.put(Throwable.class, Boolean.TRUE);
        clazzes.forEach(clz -> classified.put(clz, Boolean.TRUE));

        val retryPolicy = maximumAttempts > 0
            ? new SimpleRetryPolicy(maximumAttempts, classified, true)
            : new NeverRetryPolicy();
        retryTemplate.setBackOffPolicy(maximumAttempts > 0
            ? new FixedBackOffPolicy()
            : new NoBackOffPolicy());
        
        retryTemplate.setRetryPolicy(retryPolicy);
        retryTemplate.setThrowLastExceptionOnExhausted(true);
        retryTemplate.registerListener(new RetryListener() {
            @Override
            public boolean open(final RetryContext context, final RetryCallback __) {
                context.setAttribute("retry.maxAttempts", retryPolicy.getMaxAttempts());
                return RetryListener.super.open(context, __);
            }
        });
        return retryTemplate.execute(callback);
    }
Do and retry with a max number of attempts.

@param <T>             the type parameter
@param clazzes         the clazzes
@param callback        the callback
@param maximumAttempts the maximum attempts
@return the t
@throws Exception the exception
core/cas-server-core-util-api/src/main/java/org/apereo/cas/util/function/FunctionUtils.java