001/*
002 * nimbus-jose-jwt
003 *
004 * Copyright 2012-2022, Connect2id Ltd.
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use
007 * this file except in compliance with the License. You may obtain a copy of the
008 * License at
009 *
010 *    http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software distributed
013 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
014 * CONDITIONS OF ANY KIND, either express or implied. See the License for the
015 * specific language governing permissions and limitations under the License.
016 */
017
018package com.nimbusds.jose.jwk.source;
019
020import java.util.Objects;
021
022import net.jcip.annotations.ThreadSafe;
023
024import com.nimbusds.jose.KeySourceException;
025import com.nimbusds.jose.jwk.JWKSet;
026import com.nimbusds.jose.proc.SecurityContext;
027import com.nimbusds.jose.util.events.EventListener;
028
029
030/**
031 * {@linkplain JWKSetSource} with with retry capability to work around
032 * transient network issues. In cases when the underlying source throws a
033 * {@linkplain JWKSetUnavailableException} the retrieval is tried once again.
034 *
035 * @author Thomas Rørvik Skjølberg
036 * @version 2022-11-22
037 */
038@ThreadSafe
039public class RetryingJWKSetSource<C extends SecurityContext> extends JWKSetSourceWrapper<C> {
040        
041        
042        /**
043         * Retrial event.
044         */
045        public static class RetrialEvent<C extends SecurityContext> extends AbstractJWKSetSourceEvent<RetryingJWKSetSource<C>, C> {
046                
047                private final Exception exception;
048                
049                private RetrialEvent(final RetryingJWKSetSource<C> source,
050                                     final Exception exception,
051                                     final C securityContext) {
052                        super(source, securityContext);
053                        Objects.requireNonNull(exception);
054                        this.exception = exception;
055                }
056                
057                
058                /**
059                 * Returns the exception that caused the retrial.
060                 *
061                 * @return The exception.
062                 */
063                public Exception getException() {
064                        return exception;
065                }
066        }
067        
068        
069        private final EventListener<RetryingJWKSetSource<C>, C> eventListener;
070        
071        
072        /**
073         * Creates a new JWK set source with support for retrial.
074         *
075         * @param source        The JWK set source to decorate. Must not be
076         *                      {@code null}.
077         * @param eventListener The event listener, {@code null} if not
078         *                      specified.
079         */
080        public RetryingJWKSetSource(final JWKSetSource<C> source,
081                                    final EventListener<RetryingJWKSetSource<C>, C> eventListener) {
082                super(source);
083                this.eventListener = eventListener;
084        }
085
086        
087        @Override
088        public JWKSet getJWKSet(final JWKSetCacheRefreshEvaluator refreshEvaluator, final long currentTime, final C context)
089                throws KeySourceException {
090                
091                try {
092                        return getSource().getJWKSet(refreshEvaluator, currentTime, context);
093                        
094                } catch (JWKSetUnavailableException e) {
095                        // assume transient network issue, retry once
096                        if (eventListener != null) {
097                                eventListener.notify(new RetrialEvent<C>(this, e, context));
098                        }
099                        return getSource().getJWKSet(refreshEvaluator, currentTime, context);
100                }
101        }
102}