I want to implement a utility class which manages tokens generated by any API. The idea is simple:
It should store the current token value. The token should be initialized just before first use and then re-initialized after some time has elapsed. If the API returns an error related to the token, it should be regenerated and job should be repeated.
Here we have the utility class:
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
public abstract class TokenManager {
private volatile String token;
private ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
private ScheduledFuture<?> schedule;
public void useToken(TokenConsumer tokenConsumer) {
useToken(tokenConsumer, true);
}
private void useToken(TokenConsumer tokenConsumer, boolean retryWhenTokenExpired) {
try {
tokenConsumer.useToken(getToken());
} catch (Exception e) {
if (retryWhenTokenExpired && tokenExpired(e.getMessage())) {
System.out.println("token expired, retry");
resetToken();
useToken(tokenConsumer, false);
}
}
}
synchronized private String getToken() {
if (token == null) {
resetToken();
}
return token;
}
synchronized private void resetToken() {
if (schedule != null) {
schedule.cancel(false);
}
System.out.println("reset token");
token = generateToken();
int oneMinute = 60 * 1000;
long delay = getTokenValidityTimeMillis() - oneMinute;
schedule = scheduler.schedule(this::resetToken, delay > 0 ? delay : getTokenValidityTimeMillis(), TimeUnit.MILLISECONDS);
System.out.println("reset token finished");
}
protected abstract String generateToken();
protected abstract boolean tokenExpired(String message);
protected abstract long getTokenValidityTimeMillis();
@FunctionalInterface
public interface TokenConsumer {
void useToken(String token) throws Exception;
}
}
And here we have its simple implementation with use example:
import java.util.Random;
public class TokenManagerImpl extends TokenManager {
@Override
protected String generateToken() {
//here would go some api call which retrieves token
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "token " + new Random().nextInt();
}
@Override
protected boolean tokenExpired(String message) {
return "Token expired".equals(message);
}
@Override
protected long getTokenValidityTimeMillis() {
return 1000;
}
public static void main(String[] args) {
TokenManager tokenManager = new TokenManagerImpl();
TokenConsumer tokenConsumer = token -> {
//here would go some api call which uses token
System.out.println("using token : " + token);
};
while (true) {
tokenManager.useToken(tokenConsumer);
try {
Thread.sleep(50L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}