Moved code again
This commit is contained in:
@@ -0,0 +1,194 @@
|
||||
package licenselib;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Periodically checks a license and exposes the most recent result.
|
||||
*/
|
||||
public final class LicenseScheduler implements AutoCloseable {
|
||||
|
||||
private final ScheduledExecutorService executor;
|
||||
private final ScheduledFuture<?> task;
|
||||
private final AtomicReference<LicenseClient.LicenseResult> lastResult;
|
||||
|
||||
private LicenseScheduler(
|
||||
ScheduledExecutorService executor,
|
||||
ScheduledFuture<?> task,
|
||||
AtomicReference<LicenseClient.LicenseResult> lastResult
|
||||
) {
|
||||
this.executor = executor;
|
||||
this.task = task;
|
||||
this.lastResult = lastResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a scheduler that checks the license at the given interval.
|
||||
* @param interval Interval between checks
|
||||
* @param apiUrl Server API url
|
||||
* @param plugin Plugin id matching the one on the backend api
|
||||
* @param licenseKey License key issued by the api
|
||||
* @param serverId Server id matching the one on the backend api
|
||||
* @param onResult Optional callback invoked after every check
|
||||
* @return Scheduler handle for stopping and reading the last result
|
||||
*/
|
||||
public static LicenseScheduler startScheduler(
|
||||
Duration interval,
|
||||
String apiUrl,
|
||||
String plugin,
|
||||
String licenseKey,
|
||||
String serverId,
|
||||
Consumer<LicenseClient.LicenseResult> onResult
|
||||
) {
|
||||
Objects.requireNonNull(interval, "interval");
|
||||
if (interval.isZero() || interval.isNegative()) {
|
||||
throw new IllegalArgumentException("interval must be positive");
|
||||
}
|
||||
|
||||
AtomicReference<LicenseClient.LicenseResult> lastResult = new AtomicReference<>();
|
||||
ThreadFactory threadFactory = runnable -> {
|
||||
Thread thread = new Thread(runnable, "license-scheduler");
|
||||
thread.setDaemon(true);
|
||||
return thread;
|
||||
};
|
||||
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(threadFactory);
|
||||
|
||||
ScheduledFuture<?> task = executor.scheduleAtFixedRate(() -> {
|
||||
LicenseClient.LicenseResult result = LicenseClient.check(apiUrl, plugin, licenseKey, serverId);
|
||||
lastResult.set(result);
|
||||
if (onResult != null) {
|
||||
onResult.accept(result);
|
||||
}
|
||||
}, 0, interval.toMillis(), TimeUnit.MILLISECONDS);
|
||||
|
||||
return new LicenseScheduler(executor, task, lastResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a scheduler that retries on errors before invoking offline handling.
|
||||
* @param interval Interval between checks
|
||||
* @param apiUrl Server API url
|
||||
* @param plugin Plugin id matching the one on the backend api
|
||||
* @param licenseKey License key issued by the api
|
||||
* @param serverId Server id matching the one on the backend api
|
||||
* @param maxRetries Number of retries after a failed check
|
||||
* @param retryDelay Delay between retries
|
||||
* @param onResult Optional callback invoked after every attempt
|
||||
* @param onOffline Invoked only after all retries fail
|
||||
* @return Scheduler handle for stopping and reading the last result
|
||||
*/
|
||||
public static LicenseScheduler startSchedulerWithRetries(
|
||||
Duration interval,
|
||||
String apiUrl,
|
||||
String plugin,
|
||||
String licenseKey,
|
||||
String serverId,
|
||||
int maxRetries,
|
||||
Duration retryDelay,
|
||||
Consumer<LicenseClient.LicenseResult> onResult,
|
||||
Consumer<LicenseClient.LicenseResult> onOffline
|
||||
) {
|
||||
Objects.requireNonNull(interval, "interval");
|
||||
Objects.requireNonNull(retryDelay, "retryDelay");
|
||||
if (interval.isZero() || interval.isNegative()) {
|
||||
throw new IllegalArgumentException("interval must be positive");
|
||||
}
|
||||
if (retryDelay.isNegative()) {
|
||||
throw new IllegalArgumentException("retryDelay must not be negative");
|
||||
}
|
||||
if (maxRetries < 0) {
|
||||
throw new IllegalArgumentException("maxRetries must not be negative");
|
||||
}
|
||||
|
||||
AtomicReference<LicenseClient.LicenseResult> lastResult = new AtomicReference<>();
|
||||
ThreadFactory threadFactory = runnable -> {
|
||||
Thread thread = new Thread(runnable, "license-scheduler");
|
||||
thread.setDaemon(true);
|
||||
return thread;
|
||||
};
|
||||
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(threadFactory);
|
||||
|
||||
ScheduledFuture<?> task = executor.scheduleAtFixedRate(() -> {
|
||||
LicenseClient.LicenseResult result = attemptWithRetries(
|
||||
apiUrl,
|
||||
plugin,
|
||||
licenseKey,
|
||||
serverId,
|
||||
maxRetries,
|
||||
retryDelay,
|
||||
onResult,
|
||||
onOffline
|
||||
);
|
||||
lastResult.set(result);
|
||||
}, 0, interval.toMillis(), TimeUnit.MILLISECONDS);
|
||||
|
||||
return new LicenseScheduler(executor, task, lastResult);
|
||||
}
|
||||
|
||||
private static LicenseClient.LicenseResult attemptWithRetries(
|
||||
String apiUrl,
|
||||
String plugin,
|
||||
String licenseKey,
|
||||
String serverId,
|
||||
int maxRetries,
|
||||
Duration retryDelay,
|
||||
Consumer<LicenseClient.LicenseResult> onResult,
|
||||
Consumer<LicenseClient.LicenseResult> onOffline
|
||||
) {
|
||||
int attempt = 0;
|
||||
LicenseClient.LicenseResult result;
|
||||
|
||||
while (true) {
|
||||
result = LicenseClient.check(apiUrl, plugin, licenseKey, serverId);
|
||||
if (onResult != null) {
|
||||
onResult.accept(result);
|
||||
}
|
||||
if (!(result instanceof LicenseError)) {
|
||||
return result;
|
||||
}
|
||||
if (attempt >= maxRetries) {
|
||||
if (onOffline != null) {
|
||||
onOffline.accept(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
attempt++;
|
||||
if (!retryDelay.isZero()) {
|
||||
try {
|
||||
Thread.sleep(retryDelay.toMillis());
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the most recent license check result, or null if none has completed yet.
|
||||
* @return The last license check result, or null if not available
|
||||
*/
|
||||
public LicenseClient.LicenseResult getLastResult() {
|
||||
return lastResult.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops further checks and shuts down the scheduler.
|
||||
*/
|
||||
public void stop() {
|
||||
task.cancel(false);
|
||||
executor.shutdown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
stop();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user