Moved code again

This commit is contained in:
Patrick
2026-06-05 14:11:48 +02:00
parent dcd8c8597d
commit bc9c944b2c
5 changed files with 50 additions and 0 deletions
@@ -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();
}
}