Java API token expiration handler 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&lt;?&gt; 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 &amp;&amp; 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 &gt; 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 -&gt; {
            //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();
            }
        }
    }
}
useToken

I don't really get your expected behavior from this method. You only retry when expired, what if an exception occured while not yet expired? Nothing happens, not even a log. The same with exceptions that occur when retryWhenTokenExpired is not set, the exception gets swallowed without any trace. 


  catch (Exception e) {
    if (retryWhenTokenExpired &amp;&amp; tokenExpired(e.getMessage())) {
        System.out.println("token expired, retry");
        resetToken();
        useToken(tokenConsumer, false);
    }
  }



I would make sure the following constraint is true: either a retry is performed or an exception is propagated up the stack. In addition, on expiration, reset the token when requested so. log is an abstraction of your System.out.println.

  catch (Exception e) {
    log("error using token: " + e.getMessage());
    if (!retryWhenTokenExpired) {
        throw e;
    }
    final boolean expired = tokenExpired(e.getMessage());
    if (expired) {
        log("token expired, retry");
        resetToken();
    }
    useToken(tokenConsumer, !expired);
  }