001
002package io.vrap.rmf.base.client.oauth2;
003
004import java.time.Duration;
005import java.util.concurrent.CompletableFuture;
006import java.util.concurrent.ExecutorService;
007import java.util.concurrent.ScheduledExecutorService;
008
009import io.vrap.rmf.base.client.AuthenticationToken;
010import io.vrap.rmf.base.client.AutoCloseableService;
011
012import dev.failsafe.Failsafe;
013import dev.failsafe.FailsafeExecutor;
014import dev.failsafe.Timeout;
015import dev.failsafe.spi.Scheduler;
016
017public class InMemoryTokenSupplier extends AutoCloseableService implements RefreshableTokenSupplier {
018    private final TokenSupplier supplier;
019    private final Object lock = new Object();
020    private volatile CompletableFuture<AuthenticationToken> tokenFuture;
021
022    private final FailsafeExecutor<AuthenticationToken> failsafeExecutor;
023
024    public InMemoryTokenSupplier(TokenSupplier tokenSupplier) {
025        this(Scheduler.DEFAULT, tokenSupplier);
026    }
027
028    public InMemoryTokenSupplier(ScheduledExecutorService executorService, TokenSupplier tokenSupplier) {
029        this(Scheduler.of(executorService), tokenSupplier);
030    }
031
032    public InMemoryTokenSupplier(ExecutorService executorService, TokenSupplier tokenSupplier) {
033        this(Scheduler.of(executorService), tokenSupplier);
034    }
035
036    public InMemoryTokenSupplier(Scheduler scheduler, TokenSupplier tokenSupplier) {
037        this.supplier = tokenSupplier;
038        this.failsafeExecutor = Failsafe.with(Timeout.<AuthenticationToken> of(Duration.ofSeconds(10))).with(scheduler);
039    }
040
041    public CompletableFuture<AuthenticationToken> getToken() {
042        if (tokenFuture == null)
043            synchronized (lock) {
044                if (tokenFuture == null) {
045                    failsafeExecutor
046                            .run(() -> tokenFuture = CompletableFuture.completedFuture(supplier.getToken().join()));
047                }
048            }
049        return tokenFuture;
050    }
051
052    public CompletableFuture<AuthenticationToken> refreshToken() {
053        synchronized (lock) {
054            tokenFuture = null;
055        }
056        return getToken();
057    }
058
059    @Override
060    protected void internalClose() {
061        if (supplier instanceof AutoCloseable)
062            closeQuietly((AutoCloseable) supplier);
063    }
064}