Skip to content

Commit 22d0f1e

Browse files
committed
review from @tishun
- attemp to increase readibility and establish a clear seperation of responsibilties via breaking tokenmanager into multiple classes and interfaces. - added some comments to explain the logic
1 parent d786e23 commit 22d0f1e

File tree

8 files changed

+295
-80
lines changed

8 files changed

+295
-80
lines changed
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Copyright 2024, Redis Ltd. and Contributors All rights reserved. Licensed under the MIT License.
3+
*/
4+
package redis.clients.authentication.core;
5+
6+
import java.util.concurrent.ExecutorService;
7+
import java.util.concurrent.Executors;
8+
import java.util.concurrent.Future;
9+
import java.util.concurrent.TimeUnit;
10+
import org.slf4j.Logger;
11+
import org.slf4j.LoggerFactory;
12+
13+
/**
14+
* Dispatches requests to the identity provider asynchronously with a timeout for the request execution.
15+
*/
16+
class Dispatcher {
17+
private ExecutorService executor = Executors.newFixedThreadPool(2);
18+
private Exception error;
19+
private long tokenRequestExecTimeoutInMs;
20+
private IdentityProvider identityProvider;
21+
private Logger logger = LoggerFactory.getLogger(getClass());
22+
23+
public Dispatcher(IdentityProvider provider, long tokenRequestExecTimeoutInMs) {
24+
this.tokenRequestExecTimeoutInMs = tokenRequestExecTimeoutInMs;
25+
this.identityProvider = provider;
26+
}
27+
28+
/**
29+
* Dispatches a request to the identity provider asynchronously
30+
* with a timeout for the request execution and returns the request object
31+
* @return
32+
*/
33+
public Request requestTokenAsync() {
34+
Future<Token> request = executor.submit(() -> requestToken());
35+
return () -> request.get(tokenRequestExecTimeoutInMs, TimeUnit.MILLISECONDS);
36+
}
37+
38+
public Exception getError() {
39+
return error;
40+
}
41+
42+
public void stop() {
43+
executor.shutdown();
44+
}
45+
46+
/**
47+
* Makes the actual request to the identity provider
48+
* @return
49+
*/
50+
private Token requestToken() {
51+
error = null;
52+
try {
53+
return identityProvider.requestToken();
54+
} catch (Exception e) {
55+
error = e;
56+
logger.error("Request to identity provider failed with message: " + e.getMessage(), e);
57+
throw e;
58+
}
59+
}
60+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
* Copyright 2024, Redis Ltd. and Contributors All rights reserved. Licensed under the MIT License.
3+
*/
4+
package redis.clients.authentication.core;
5+
6+
import java.util.concurrent.ExecutionException;
7+
import java.util.concurrent.Executors;
8+
import java.util.concurrent.ScheduledExecutorService;
9+
import java.util.concurrent.TimeUnit;
10+
import java.util.function.Supplier;
11+
12+
/**
13+
* Schedules a task for token renewal.
14+
*/
15+
class RenewalScheduler {
16+
private ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
17+
private RenewalTask lastTask;
18+
private Supplier<Token> renewToken;
19+
private boolean stopped = false;
20+
21+
public RenewalScheduler(Supplier<Token> renewToken) {
22+
this.renewToken = renewToken;
23+
}
24+
25+
/**
26+
* Schedules a task to renew the token with a given delay
27+
* Wraps the supplier function into RenewalTask
28+
* @param delay
29+
* @return
30+
*/
31+
public RenewalTask scheduleNext(long delay) {
32+
// Schedule the task to run after the given delay
33+
lastTask = new RenewalTask(
34+
scheduler.schedule(() -> renewToken.get(), delay, TimeUnit.MILLISECONDS));
35+
return lastTask;
36+
}
37+
38+
/**
39+
* Returns the last task that was scheduled
40+
* @return
41+
*/
42+
public RenewalTask getLastTask() {
43+
return lastTask;
44+
}
45+
46+
/**
47+
* Waits for given task to complete
48+
* If there is an execution error in the task, it throws the same exception
49+
* It keeps following if there are consecutive tasks until a non-null result is returned or an exception occurs
50+
* This makes the caller thread to wait until a first token is received with or after the pendingTask
51+
* @param pendingTask
52+
* @throws InterruptedException
53+
* @throws ExecutionException
54+
*/
55+
public void waitFor(RenewalTask pendingTask) throws InterruptedException, ExecutionException {
56+
while (!stopped && pendingTask.waitForResultOrError() == null) {
57+
pendingTask = getLastTask();
58+
}
59+
}
60+
61+
public void stop() {
62+
stopped = true;
63+
lastTask.cancel();
64+
scheduler.shutdown();
65+
}
66+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Copyright 2024, Redis Ltd. and Contributors
3+
* All rights reserved.
4+
*
5+
* Licensed under the MIT License.
6+
*/
7+
package redis.clients.authentication.core;
8+
9+
import java.util.concurrent.ExecutionException;
10+
import java.util.concurrent.ScheduledFuture;
11+
12+
class RenewalTask {
13+
14+
private ScheduledFuture<Token> future;
15+
16+
public RenewalTask(ScheduledFuture<Token> future) {
17+
this.future = future;
18+
}
19+
20+
public Token waitForResultOrError() throws InterruptedException, ExecutionException {
21+
return future.get();
22+
}
23+
24+
public void cancel() {
25+
future.cancel(true);
26+
}
27+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/*
2+
* Copyright 2024, Redis Ltd. and Contributors
3+
* All rights reserved.
4+
*
5+
* Licensed under the MIT License.
6+
*/
7+
package redis.clients.authentication.core;
8+
9+
import java.util.concurrent.ExecutionException;
10+
import java.util.concurrent.TimeoutException;
11+
12+
interface Request {
13+
14+
public Token getResult() throws InterruptedException, ExecutionException, TimeoutException;
15+
}

0 commit comments

Comments
 (0)