@@ -44,19 +44,57 @@ public class DefaultCredentialsRefreshService implements CredentialsRefreshServi
4444
4545 private static final Logger LOGGER = LoggerFactory .getLogger (DefaultCredentialsRefreshService .class );
4646
47+ /**
48+ * Scheduler used to schedule credentials refresh.
49+ * <p>
50+ * Default is a single-threaded scheduler, which should be enough for most scenarios, assuming
51+ * that credentials expire after a few minutes or hours. This default scheduler
52+ * is automatically disposed of when the {@link DefaultCredentialsRefreshService} is closed.
53+ * <p>
54+ * If an external scheduler is passed in, it is the developer's responsibility to
55+ * close it.
56+ */
4757 private final ScheduledExecutorService scheduler ;
4858
4959 private final ConcurrentMap <CredentialsProvider , CredentialsProviderState > credentialsProviderStates = new ConcurrentHashMap <>();
5060
5161 private final boolean privateScheduler ;
5262
63+ /**
64+ * Strategy to schedule credentials refresh after credentials retrieval.
65+ * <p>
66+ * Typical strategies schedule refresh after a ratio of the time before expiration
67+ * (e.g. 80 % of the time before expiration) or after a fixed time before
68+ * expiration (e.g. 20 seconds before credentials expire).
69+ *
70+ * @see #ratioRefreshDelayStrategy(double)
71+ * @see #fixedDelayBeforeExpirationRefreshDelayStrategy(Duration)
72+ */
5373 private final Function <Duration , Duration > refreshDelayStrategy ;
5474
55- private final Function <Duration , Boolean > needRefreshStrategy ;
75+ /**
76+ * Strategy to provide a hint about whether credentials should be renewed now or not before attempting to connect.
77+ * <p>
78+ * This can avoid a connection to use almost expired credentials if this connection
79+ * is created just before credentials are refreshed in the background, but does not
80+ * benefit from the refresh.
81+ * <p>
82+ * Note setting such a strategy may require knowledge of the credentials validity and must be consistent
83+ * with the {@link #refreshDelayStrategy} chosen. For example, for a validity of 60 minutes and
84+ * a {@link #refreshDelayStrategy} that instructs to refresh 10 minutes before credentials expire, this
85+ * strategy could hint that credentials that expire in 11 minutes or less (1 minute before a refresh is actually
86+ * scheduled) should be refreshed, which would trigger an early refresh.
87+ * <p>
88+ * The default strategy always return false.
89+ */
90+ private final Function <Duration , Boolean > approachingExpirationStrategy ;
5691
57- public DefaultCredentialsRefreshService (ScheduledExecutorService scheduler , Function <Duration , Duration > refreshDelayStrategy , Function <Duration , Boolean > needRefreshStrategy ) {
92+ public DefaultCredentialsRefreshService (ScheduledExecutorService scheduler , Function <Duration , Duration > refreshDelayStrategy , Function <Duration , Boolean > approachingExpirationStrategy ) {
93+ if (refreshDelayStrategy == null ) {
94+ throw new IllegalArgumentException ("Refresh delay strategy can not be null" );
95+ }
5896 this .refreshDelayStrategy = refreshDelayStrategy ;
59- this .needRefreshStrategy = needRefreshStrategy ;
97+ this .approachingExpirationStrategy = approachingExpirationStrategy == null ? duration -> false : approachingExpirationStrategy ;
6098 if (scheduler == null ) {
6199 this .scheduler = Executors .newScheduledThreadPool (1 );
62100 privateScheduler = true ;
@@ -69,8 +107,8 @@ public DefaultCredentialsRefreshService(ScheduledExecutorService scheduler, Func
69107 /**
70108 * Delay before refresh is a ratio of the time before expiration.
71109 * <p>
72- * E.g. if time before expiration is 60 seconds and specified ratio is 0.8, refresh will
73- * be scheduled in 60 x 0.8 = 48 seconds .
110+ * E.g. if time before expiration is 60 minutes and specified ratio is 0.8, refresh will
111+ * be scheduled in 60 x 0.8 = 48 minutes .
74112 *
75113 * @param ratio
76114 * @return the delay before refreshing
@@ -82,8 +120,8 @@ public static Function<Duration, Duration> ratioRefreshDelayStrategy(double rati
82120 /**
83121 * Delay before refresh is <code>time before expiration - specified duration</code>.
84122 * <p>
85- * E.g. if time before expiration is 60 seconds and specified duration is 20 seconds , refresh will
86- * be scheduled in 60 - 20 = 40 seconds .
123+ * E.g. if time before expiration is 60 minutes and specified duration is 10 minutes , refresh will
124+ * be scheduled in 60 - 10 = 50 minutes .
87125 *
88126 * @param duration
89127 * @return the delay before refreshing
@@ -98,8 +136,8 @@ public static Function<Duration, Duration> fixedDelayBeforeExpirationRefreshDela
98136 * @param limitBeforeExpiration
99137 * @return true if credentials should be refreshed, false otherwise
100138 */
101- public static Function <Duration , Boolean > fixedTimeNeedRefreshStrategy (Duration limitBeforeExpiration ) {
102- return new FixedTimeNeedRefreshStrategy (limitBeforeExpiration .toMillis ());
139+ public static Function <Duration , Boolean > fixedTimeApproachingExpirationStrategy (Duration limitBeforeExpiration ) {
140+ return new FixedTimeApproachingExpirationStrategy (limitBeforeExpiration .toMillis ());
103141 }
104142
105143 private static Runnable refresh (ScheduledExecutorService scheduler , CredentialsProviderState credentialsProviderState ,
@@ -157,8 +195,8 @@ public void unregister(CredentialsProvider credentialsProvider, String registrat
157195 }
158196
159197 @ Override
160- public boolean needRefresh (Duration timeBeforeExpiration ) {
161- return this .needRefreshStrategy .apply (timeBeforeExpiration );
198+ public boolean isApproachingExpiration (Duration timeBeforeExpiration ) {
199+ return this .approachingExpirationStrategy .apply (timeBeforeExpiration );
162200 }
163201
164202 public void close () {
@@ -167,11 +205,11 @@ public void close() {
167205 }
168206 }
169207
170- private static class FixedTimeNeedRefreshStrategy implements Function <Duration , Boolean > {
208+ private static class FixedTimeApproachingExpirationStrategy implements Function <Duration , Boolean > {
171209
172210 private final long limitBeforeExpiration ;
173211
174- private FixedTimeNeedRefreshStrategy (long limitBeforeExpiration ) {
212+ private FixedTimeApproachingExpirationStrategy (long limitBeforeExpiration ) {
175213 this .limitBeforeExpiration = limitBeforeExpiration ;
176214 }
177215
@@ -340,7 +378,7 @@ public static class DefaultCredentialsRefreshServiceBuilder {
340378
341379 private Function <Duration , Duration > refreshDelayStrategy = ratioRefreshDelayStrategy (0.8 );
342380
343- private Function <Duration , Boolean > needRefreshStrategy = ttl -> false ;
381+ private Function <Duration , Boolean > approachingExpirationStrategy = ttl -> false ;
344382
345383 public DefaultCredentialsRefreshServiceBuilder scheduler (ScheduledThreadPoolExecutor scheduler ) {
346384 this .scheduler = scheduler ;
@@ -352,13 +390,13 @@ public DefaultCredentialsRefreshServiceBuilder refreshDelayStrategy(Function<Dur
352390 return this ;
353391 }
354392
355- public DefaultCredentialsRefreshServiceBuilder needRefreshStrategy (Function <Duration , Boolean > needRefreshStrategy ) {
356- this .needRefreshStrategy = needRefreshStrategy ;
393+ public DefaultCredentialsRefreshServiceBuilder approachingExpirationStrategy (Function <Duration , Boolean > approachingExpirationStrategy ) {
394+ this .approachingExpirationStrategy = approachingExpirationStrategy ;
357395 return this ;
358396 }
359397
360398 public DefaultCredentialsRefreshService build () {
361- return new DefaultCredentialsRefreshService (scheduler , refreshDelayStrategy , needRefreshStrategy );
399+ return new DefaultCredentialsRefreshService (scheduler , refreshDelayStrategy , approachingExpirationStrategy );
362400 }
363401
364402 }
0 commit comments