io.sphere.sdk.client.AutoRefreshSphereAccessTokenSupplierImpl Maven / Gradle / Ivy
package io.sphere.sdk.client;
import io.sphere.sdk.client.AuthActorProtocol.*;
import io.sphere.sdk.http.HttpClient;
import io.sphere.sdk.utils.CompletableFutureUtils;
import java.time.ZonedDateTime;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import static io.sphere.sdk.client.SphereAuth.AUTH_LOGGER;
/**
* Holds OAuth access tokenCache for accessing protected Sphere HTTP API endpoints.
* Refreshes the access token as needed automatically.
*/
final class AutoRefreshSphereAccessTokenSupplierImpl extends AutoCloseableService implements SphereAccessTokenSupplier {
private volatile CompletableFuture currentAccessTokenFuture = new CompletableFuture<>();
private volatile Optional currentTokensOption = Optional.empty();
private final Actor tokenActor = new TokenActor();
private final Actor authActor;
private AutoRefreshSphereAccessTokenSupplierImpl(final SphereAuthConfig config, final HttpClient httpClient, final boolean closeHttpClient) {
final TokensSupplier internalTokensSupplier = TokensSupplierImpl.of(config, httpClient, closeHttpClient);
authActor = new AuthActor(internalTokensSupplier);
authActor.tell(new SubscribeMessage(tokenActor));
}
@Override
public CompletionStage get() {
return currentAccessTokenFuture;
}
@Override
protected void internalClose() {
closeQuietly(authActor);
closeQuietly(tokenActor);
}
public static SphereAccessTokenSupplier createAndBeginRefreshInBackground(final SphereAuthConfig config, final HttpClient httpClient, final boolean closeHttpClient) {
return new AutoRefreshSphereAccessTokenSupplierImpl(config, httpClient, closeHttpClient);
}
private class TokenActor extends Actor {
@Override
protected void receive(final Object message) {
receiveBuilder(message)
.when(TokenDeliveredMessage.class, m -> {
if (!currentTokensOption.isPresent() || currentTokenIsOlder(m.tokens)) {
updateToken(m.tokens);
}
})
.when(TokenDeliveryFailedMessage.class, m -> {
final boolean hasInvalidCredentials = m.cause.getCause() != null && m.cause.getCause() instanceof InvalidClientCredentialsException;
if (hasInvalidCredentials) {
AUTH_LOGGER.error(() -> "Invalid client credentials shutting down.", m.cause);
currentAccessTokenFuture.completeExceptionally(m.cause);//in case it is still empty
currentAccessTokenFuture = CompletableFutureUtils.failed(m.cause);//in case it was not empty
close();
} else if (!currentTokensOption.isPresent()) {
currentAccessTokenFuture.completeExceptionally(m.cause);
} else if (lastTokenIsStillValid()) {
//keep the old token
} else {
currentTokensOption = Optional.empty();
currentAccessTokenFuture = CompletableFutureUtils.failed(m.cause);
}
});
}
}
/**
* if the last token has no expire time it true
* @return
*/
private boolean lastTokenIsStillValid() {
if (currentTokensOption.isPresent()) {
final Tokens oldTokens = currentTokensOption.get();
return oldTokens.getExpiresZonedDateTime().map(expireTime -> expireTime.isAfter(ZonedDateTime.now())).orElse(true);
} else {
return false;
}
}
private boolean currentTokenIsOlder(final Tokens newTokens) {
return (currentTokensOption.isPresent() && oldExpiringZonedDateTime().isBefore(newExpiringZonedDateTime(newTokens)));
}
private ZonedDateTime newExpiringZonedDateTime(final Tokens newTokens) {
return newTokens.getExpiresZonedDateTime().orElseGet(() -> ZonedDateTime.now().plusSeconds(30 * 60));
}
private ZonedDateTime oldExpiringZonedDateTime() {
return currentTokensOption.get().getExpiresZonedDateTime().orElseGet(() -> ZonedDateTime.now());
}
private void updateToken(final Tokens tokens) {
currentTokensOption = Optional.of(tokens);
final String accessToken = tokens.getAccessToken();
if (currentAccessTokenFuture.isDone()) {
currentAccessTokenFuture = CompletableFutureUtils.successful(accessToken);
} else {
currentAccessTokenFuture.complete(accessToken);
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy