com.sap.cloud.mt.tools.AsyncPolling Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of multi-tenant-subscription Show documentation
Show all versions of multi-tenant-subscription Show documentation
Spring Boot Enablement Parent
/*******************************************************************************
* © 2019-2024 SAP SE or an SAP affiliate company. All rights reserved.
******************************************************************************/
package com.sap.cloud.mt.tools;
import java.time.Duration;
import java.util.TimerTask;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Supplier;
/**
* Class that provides an asynchronous polling functionality executed in an own thread.
*/
public class AsyncPolling {
private final Duration delay;
private final Duration period;
private final Duration maximumRuntime;
private final ConcurrentHashMap> futures = new ConcurrentHashMap<>();
private AsyncPolling(Duration delay, Duration period, Duration maximumRuntime) {
this.delay = delay;
this.period = period;
this.maximumRuntime = maximumRuntime;
}
/**
* Start the polling operation
*
* @param action is a lambda expression that is executed periodically until the operation is finished or the maximum runtime is reached
* @param finalAction is an optional lambda expression called after the polling.
* @param is the type of the result
*/
public void execute(Supplier> action, Consumer> finalAction) {
final PollingResponse pollingResponse = new PollingResponse<>();
UUID futureUuid = UUID.randomUUID();
TimerTask task = createNewTask(action, finalAction, pollingResponse, futureUuid);
ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
futures.put(futureUuid, executorService.scheduleAtFixedRate(task, delay.toNanos(), period.toNanos(), TimeUnit.NANOSECONDS));
}
private TimerTask createNewTask(Supplier> action, Consumer> finalAction,
PollingResponse pollingResponse, UUID futureUuid) {
final long startTime = System.currentTimeMillis();
return new TimerTask() {
@Override
public void run() {
pollingResponse.copyFrom(action.get());
if (pollingResponse.isFinished() || System.currentTimeMillis() - startTime >= maximumRuntime.toMillis()) {
if (finalAction != null) {
finalAction.accept(pollingResponse);
}
//The future is set externally, after scheduleAtFixedRate is called. Therefore make sure that it is set
Wait wait = Wait.createBuilder().waitTime(Duration.ofMillis(1))
.maximumTime(Duration.ofMillis(1000)).build();
wait.waitUntil(() -> futures.contains(futureUuid));
ScheduledFuture> future = futures.get(futureUuid);
futures.remove(futureUuid);
//if future is still null, then we live with the runtime exception
future.cancel(false);
}
}
};
}
/**
* @return a builder for the asynchronous polling class
*/
public static AsyncPollingBuilder createBuilder() {
return AsyncPollingBuilder.create();
}
/**
* Builder for the asynchronous builder
*/
public static final class AsyncPollingBuilder {
private Duration delay;
private Duration period;
private Duration maximumRuntime;
private static AsyncPollingBuilder create() {
return new AsyncPollingBuilder();
}
/**
* @param delay is the time after which the action is called the first time
* @return builder
*/
public AsyncPollingBuilder delay(Duration delay) {
this.delay = delay;
return this;
}
/**
* @param period is the time interval after which the action is called again
* @return builder
*/
public AsyncPollingBuilder period(Duration period) {
this.period = period;
return this;
}
/**
* @param maximumRuntime is the maximum time the polling is tried
* @return builder
*/
public AsyncPollingBuilder maximumRuntime(Duration maximumRuntime) {
this.maximumRuntime = maximumRuntime;
return this;
}
/**
* @return the asynchronous builder
*/
public AsyncPolling build() {
return new AsyncPolling(delay, period, maximumRuntime);
}
}
}