diff --git a/buildSrc/src/main/kotlin/Dependencies.kt b/buildSrc/src/main/kotlin/Dependencies.kt index f631126..aefc24e 100644 --- a/buildSrc/src/main/kotlin/Dependencies.kt +++ b/buildSrc/src/main/kotlin/Dependencies.kt @@ -1,4 +1,4 @@ -private fun Map>.ver(minor: Int, patch: Int):String = "${minor}.${this[minor]?.get(patch)}" +private fun Map>.ver(minor: Int, patch: Int): String = "${minor}.${this[minor]?.get(patch)}" object PlayioPlugin { @@ -25,6 +25,16 @@ object UtilLibs { const val jetbrainsAnnotations = "org.jetbrains:annotations:${Version.jetbrainsAnnotations}" } +object LogLibs { + + object Version { + + const val logback = "1.4.8" + } + + const val logback = "ch.qos.logback:logback-classic:${Version.logback}" +} + object JacksonLibs { object Version { @@ -34,7 +44,6 @@ object JacksonLibs { const val annotations = "com.fasterxml.jackson.core:jackson-annotations:${Version.jackson}" const val databind = "com.fasterxml.jackson.core:jackson-databind:${Version.jackson}" - const val datetime = "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:${Version.jackson}" } object TestLibs { @@ -55,22 +64,20 @@ object VertxLibs { object Version { - private val pool = mapOf(2 to (0..7).toList(), 3 to (0..6).toList(), 4 to (0..0).toList()) - @JvmField val vertxCore = "4.${pool.ver(3, 5)}" - @JvmField val vertxSQL = "4.${pool.ver(3, 5)}" - const val vertxJunit = "4.2.5" + private val pool = mapOf(2 to (0..7).toList(), 3 to (0..6).toList(), 4 to (0..4).toList()) + @JvmField val defaultVersion = "4.${pool.ver(4, 4)}" } - @JvmField val core = "io.vertx:vertx-core:${Version.vertxCore}" - @JvmField val junit5 = "io.vertx:vertx-junit5:${Version.vertxJunit}" + @JvmField val core = "io.vertx:vertx-core:${Version.defaultVersion}" + @JvmField val junit5 = "io.vertx:vertx-junit5:${Version.defaultVersion}" + @JvmField val rx3 = "io.vertx:vertx-rx-java3:${Version.defaultVersion}" } -object ValidationLibs { +object MutinyLibs { object Version { - const val api = "3.0.2" - const val hibernate = "8.0.0.Final" + + const val mutiny = "2.27.0" } - const val api = "jakarta.validation:jakarta.validation-api:${Version.api}" - const val hibernate = "org.hibernate.validator:hibernate-validator:${Version.hibernate}" + const val core = "io.smallrye.reactive:smallrye-mutiny-vertx-core:${Version.mutiny}" } diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 0fbb472..5ab5a57 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -1,5 +1,8 @@ +import cloud.playio.gradle.generator.codegen.SourceSetName + plugins { `java-test-fixtures` + id(PlayioPlugin.codegen) } @@ -7,28 +10,30 @@ oss { baseName.set("schedulerx") title.set("Scheduler.x") } -val vertxVersion = "4.0.0" -val vertxCore = "io.vertx:vertx-core:${vertxVersion}" -val vertx5Junit = "io.vertx:vertx-junit5:${vertxVersion}" + +codegen { + vertx { + version.set(VertxLibs.Version.defaultVersion) + sources.addAll(arrayOf(SourceSetName.MAIN)) + } +} dependencies { - api(vertxCore) - api("org.slf4j:slf4j-api:1.7.30") + api(VertxLibs.core) + compileOnly(JacksonLibs.annotations) compileOnly(JacksonLibs.databind) compileOnly(UtilLibs.jetbrainsAnnotations) - annotationProcessor(UtilLibs.jetbrainsAnnotations) + codeGenerator(VertxLibs.rx3) + codeGenerator(MutinyLibs.core) - testImplementation(vertx5Junit) testImplementation(TestLibs.junit5Params) testImplementation(JacksonLibs.databind) - testImplementation("ch.qos.logback:logback-classic:1.2.3") + testImplementation(LogLibs.logback) testCompileOnly(UtilLibs.jetbrainsAnnotations) - testAnnotationProcessor(UtilLibs.jetbrainsAnnotations) testFixturesApi(TestLibs.junit5Api) testFixturesApi(TestLibs.junit5Engine) testFixturesApi(TestLibs.junit5Vintage) - testFixturesApi(vertx5Junit) + testFixturesApi(VertxLibs.junit5) testFixturesCompileOnly(UtilLibs.jetbrainsAnnotations) - testFixturesAnnotationProcessor(UtilLibs.jetbrainsAnnotations) } diff --git a/core/src/main/java/io/github/zero88/schedulerx/CronTaskExecutor.java b/core/src/main/java/io/github/zero88/schedulerx/CronTaskExecutor.java deleted file mode 100644 index 2c19eb6..0000000 --- a/core/src/main/java/io/github/zero88/schedulerx/CronTaskExecutor.java +++ /dev/null @@ -1,10 +0,0 @@ -package io.github.zero88.schedulerx; - -import io.github.zero88.schedulerx.impl.CronTaskExecutorBuilder; -import io.github.zero88.schedulerx.trigger.CronTrigger; - -public interface CronTaskExecutor extends TriggerTaskExecutor { - - static CronTaskExecutorBuilder builder() { return new CronTaskExecutorBuilder(); } - -} diff --git a/core/src/main/java/io/github/zero88/schedulerx/IntervalTaskExecutor.java b/core/src/main/java/io/github/zero88/schedulerx/IntervalTaskExecutor.java deleted file mode 100644 index 98b83ff..0000000 --- a/core/src/main/java/io/github/zero88/schedulerx/IntervalTaskExecutor.java +++ /dev/null @@ -1,10 +0,0 @@ -package io.github.zero88.schedulerx; - -import io.github.zero88.schedulerx.impl.IntervalTaskExecutorBuilder; -import io.github.zero88.schedulerx.trigger.IntervalTrigger; - -public interface IntervalTaskExecutor extends TriggerTaskExecutor { - - static IntervalTaskExecutorBuilder builder() { return new IntervalTaskExecutorBuilder(); } - -} diff --git a/core/src/main/java/io/github/zero88/schedulerx/TaskExecutor.java b/core/src/main/java/io/github/zero88/schedulerx/TaskExecutor.java index b8a9300..25bd3e2 100644 --- a/core/src/main/java/io/github/zero88/schedulerx/TaskExecutor.java +++ b/core/src/main/java/io/github/zero88/schedulerx/TaskExecutor.java @@ -2,39 +2,26 @@ import org.jetbrains.annotations.NotNull; -import io.vertx.core.Vertx; +import io.vertx.codegen.annotations.GenIgnore; +import io.vertx.codegen.annotations.VertxGen; import io.vertx.core.WorkerExecutor; /** * Represents for an executor run {@code task} in conditional loop * - * @see TriggerTaskExecutor * @since 1.0.0 */ -public interface TaskExecutor { - - /** - * Vertx - * - * @return vertx - */ - @NotNull Vertx vertx(); +@VertxGen(concrete = false) +public interface TaskExecutor extends TaskExecutorProperties { /** * Task executor state * * @return task executor state */ + @GenIgnore(GenIgnore.PERMITTED_TYPE) @NotNull TaskExecutorState state(); - /** - * Defines a task executor monitor - * - * @return task executor monitor - * @see TaskExecutorMonitor - */ - @NotNull TaskExecutorMonitor monitor(); - /** * Start and run in {@code Vertx worker thread pool} */ @@ -53,6 +40,7 @@ public interface TaskExecutor { * * @param executionContext execution context */ + @GenIgnore(GenIgnore.PERMITTED_TYPE) void executeTask(@NotNull TaskExecutionContext executionContext); /** diff --git a/core/src/main/java/io/github/zero88/schedulerx/TaskExecutorLogMonitor.java b/core/src/main/java/io/github/zero88/schedulerx/TaskExecutorLogMonitor.java index 80bd0af..e7d5f9f 100644 --- a/core/src/main/java/io/github/zero88/schedulerx/TaskExecutorLogMonitor.java +++ b/core/src/main/java/io/github/zero88/schedulerx/TaskExecutorLogMonitor.java @@ -1,47 +1,49 @@ package io.github.zero88.schedulerx; import org.jetbrains.annotations.NotNull; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; + +import io.vertx.core.impl.logging.Logger; +import io.vertx.core.impl.logging.LoggerFactory; /** - * Represents for log monitor + * Represents for a log monitor that observes and do log on each lifecycle event of the task executor. * * @since 1.0.0 */ public interface TaskExecutorLogMonitor extends TaskExecutorMonitor { Logger LOGGER = LoggerFactory.getLogger(TaskExecutorLogMonitor.class); - TaskExecutorMonitor LOG_MONITOR = new TaskExecutorLogMonitor() {}; + TaskExecutorLogMonitor LOG_MONITOR = new TaskExecutorLogMonitor() { }; @Override default void onUnableSchedule(@NotNull TaskResult result) { - LOGGER.error("Unable schedule task at [{}] due to error", result.unscheduledAt(), result.error()); + LOGGER.error("Unable schedule task at [" + result.unscheduledAt() + "] due to error", result.error()); } @Override default void onSchedule(@NotNull TaskResult result) { if (result.isReschedule()) { - LOGGER.debug("TaskExecutor is rescheduled at [{}] round [{}]", result.rescheduledAt(), result.round()); + LOGGER.debug( + "TaskExecutor is rescheduled at [" + result.rescheduledAt() + "] round [" + result.round() + "]"); } else { - LOGGER.debug("TaskExecutor is available at [{}]", result.availableAt()); + LOGGER.debug("TaskExecutor is available at [" + result.availableAt() + "]"); } } @Override default void onMisfire(@NotNull TaskResult result) { - LOGGER.debug("Misfire tick [{}] at [{}]", result.tick(), result.triggeredAt()); + LOGGER.debug("Misfire tick [" + result.tick() + "] at [" + result.triggeredAt() + "]"); } @Override default void onEach(@NotNull TaskResult result) { - LOGGER.debug("Finish round [{}] - Is Error [{}] | Executed at [{}] - Finished at [{}]", result.round(), - result.isError(), result.executedAt(), result.finishedAt()); + LOGGER.debug("Finish round [" + result.round() + "] - Is Error [" + result.isError() + "] | Executed at [" + + result.executedAt() + "] - Finished at [" + result.finishedAt() + "]"); } @Override default void onCompleted(@NotNull TaskResult result) { - LOGGER.debug("Completed task in round [{}] at [{}]", result.round(), result.completedAt()); + LOGGER.debug("Completed task in round [" + result.round() + "] at [" + result.completedAt() + "]"); } } diff --git a/core/src/main/java/io/github/zero88/schedulerx/TaskExecutorMonitor.java b/core/src/main/java/io/github/zero88/schedulerx/TaskExecutorMonitor.java index e5cb592..14d3d87 100644 --- a/core/src/main/java/io/github/zero88/schedulerx/TaskExecutorMonitor.java +++ b/core/src/main/java/io/github/zero88/schedulerx/TaskExecutorMonitor.java @@ -3,7 +3,9 @@ import org.jetbrains.annotations.NotNull; /** - * Represents for monitor that watches lifecycle event in executor + * Represents for a monitor that watches lifecycle event in executor. + *

+ * It can be used to persist or distribute the task result per each round. * * @see TaskResult * @since 1.0.0 diff --git a/core/src/main/java/io/github/zero88/schedulerx/TaskExecutorProperties.java b/core/src/main/java/io/github/zero88/schedulerx/TaskExecutorProperties.java new file mode 100644 index 0000000..1da1b69 --- /dev/null +++ b/core/src/main/java/io/github/zero88/schedulerx/TaskExecutorProperties.java @@ -0,0 +1,53 @@ +package io.github.zero88.schedulerx; + +import org.jetbrains.annotations.ApiStatus.Internal; +import org.jetbrains.annotations.NotNull; + +import io.vertx.codegen.annotations.GenIgnore; +import io.vertx.codegen.annotations.VertxGen; +import io.vertx.core.Vertx; + +/** + * Shared immutable fields between TaskExecutor and its builder + * + * @since 2.0.0 + */ +@Internal +@VertxGen(concrete = false) +public interface TaskExecutorProperties { + + /** + * Vertx + * + * @return vertx + */ + @NotNull Vertx vertx(); + + /** + * Defines a task executor monitor + * + * @return task executor monitor + * @see TaskExecutorMonitor + */ + @GenIgnore(GenIgnore.PERMITTED_TYPE) + @NotNull TaskExecutorMonitor monitor(); + + /** + * Task to execute per round + * + * @return task + * @see Task + */ + @GenIgnore(GenIgnore.PERMITTED_TYPE) + @NotNull Task task(); + + /** + * Defines job data as input task data + * + * @return job data + * @see JobData + */ + @GenIgnore(GenIgnore.PERMITTED_TYPE) + @NotNull JobData jobData(); + +} diff --git a/core/src/main/java/io/github/zero88/schedulerx/TaskResult.java b/core/src/main/java/io/github/zero88/schedulerx/TaskResult.java index 3b1d2b4..3e53e00 100644 --- a/core/src/main/java/io/github/zero88/schedulerx/TaskResult.java +++ b/core/src/main/java/io/github/zero88/schedulerx/TaskResult.java @@ -5,8 +5,6 @@ import org.jetbrains.annotations.Nullable; -import io.github.zero88.schedulerx.impl.TaskResultBuilder; - /** * Represents for task result will be pass on each event of {@link TaskExecutorMonitor} * @@ -15,8 +13,6 @@ */ public interface TaskResult { - static TaskResultBuilder builder() { return new TaskResultBuilder(); } - /** * Only {@code not null} in {@link TaskExecutorMonitor#onUnableSchedule(TaskResult)} * diff --git a/core/src/main/java/io/github/zero88/schedulerx/TriggerTaskExecutor.java b/core/src/main/java/io/github/zero88/schedulerx/TriggerTaskExecutor.java index 586cd18..94f563e 100644 --- a/core/src/main/java/io/github/zero88/schedulerx/TriggerTaskExecutor.java +++ b/core/src/main/java/io/github/zero88/schedulerx/TriggerTaskExecutor.java @@ -9,6 +9,7 @@ * * @param Type of Trigger * @see Trigger + * @see TaskExecutor * @since 1.0.0 */ public interface TriggerTaskExecutor extends TaskExecutor { @@ -20,20 +21,4 @@ public interface TriggerTaskExecutor extends TaskExecutor { */ @NotNull T trigger(); - /** - * Task to execute per round - * - * @return task - * @see Task - */ - @NotNull Task task(); - - /** - * Defines job data as input task data - * - * @return job data - * @see JobData - */ - @NotNull JobData jobData(); - } diff --git a/core/src/main/java/io/github/zero88/schedulerx/TriggerTaskExecutorBuilder.java b/core/src/main/java/io/github/zero88/schedulerx/TriggerTaskExecutorBuilder.java index f89b4fc..c731803 100644 --- a/core/src/main/java/io/github/zero88/schedulerx/TriggerTaskExecutorBuilder.java +++ b/core/src/main/java/io/github/zero88/schedulerx/TriggerTaskExecutorBuilder.java @@ -6,6 +6,8 @@ import io.vertx.core.Vertx; /** + * Represents for the high level of a builder that construct {@code TriggerTaskExecutor} + * * @param Type of Trigger * @param Type of Trigger Task Executor * @param Type of Executor Builder @@ -14,7 +16,10 @@ * @since 2.0.0 */ public interface TriggerTaskExecutorBuilder, - SELF extends TriggerTaskExecutorBuilder> { + SELF extends TriggerTaskExecutorBuilder> + extends TaskExecutorProperties { + + @NotNull TRIGGER trigger(); @NotNull SELF setVertx(@NotNull Vertx vertx); @@ -26,16 +31,6 @@ public interface TriggerTaskExecutorBuilder Type of trigger + */ public abstract class AbstractTaskExecutor implements TriggerTaskExecutor { + @SuppressWarnings("java:S3416") protected static final Logger LOGGER = LoggerFactory.getLogger(TaskExecutor.class); @NotNull private final Vertx vertx; @@ -36,6 +44,9 @@ public abstract class AbstractTaskExecutor implements Trigger private final Task task; @NotNull private final T trigger; + private final Lock lock = new ReentrantLock(); + private boolean didTriggerValidation = false; + private IllegalArgumentException invalidTrigger; protected AbstractTaskExecutor(@NotNull Vertx vertx, @NotNull TaskExecutorMonitor monitor, @NotNull JobData jobData, @NotNull Task task, @NotNull T trigger) { @@ -48,39 +59,57 @@ protected AbstractTaskExecutor(@NotNull Vertx vertx, @NotNull TaskExecutorMonito } @Override - public @NotNull TaskExecutorState state() { return state; } + public final @NotNull TaskExecutorState state() { return state; } @Override - public @NotNull Vertx vertx() { return this.vertx; } + public final @NotNull Vertx vertx() { return this.vertx; } @Override - public @NotNull TaskExecutorMonitor monitor() { return this.monitor; } + public final @NotNull TaskExecutorMonitor monitor() { return this.monitor; } @Override - public @NotNull JobData jobData() { return this.jobData; } + public final @NotNull JobData jobData() { return this.jobData; } @Override - public @NotNull Task task() { return this.task; } + public final @NotNull Task task() { return this.task; } @Override - @SuppressWarnings("unchecked") - public @NotNull T trigger() { return (T) this.trigger.validate(); } + public final @NotNull T trigger() { + lock.lock(); + try { + if (didTriggerValidation) { + if (invalidTrigger == null) { return trigger; } + throw invalidTrigger; + } + try { + //noinspection unchecked + return (T) this.trigger.validate(); + } catch (IllegalArgumentException ex) { + this.invalidTrigger = ex; + throw ex; + } finally { + didTriggerValidation = true; + } + } finally { + lock.unlock(); + } + } @Override - public void start(WorkerExecutor workerExecutor) { + public final void start(WorkerExecutor workerExecutor) { this.addTimer(Promise.promise(), workerExecutor) .onSuccess(this::onReceiveTimer) - .onFailure(t -> monitor().onUnableSchedule(TaskResult.builder() - .setTick(state().tick()) - .setRound(state().round()) - .setAvailableAt(state().availableAt()) - .setUnscheduledAt(Instant.now()) - .setError(t) - .build())); + .onFailure(t -> monitor().onUnableSchedule(TaskResultImpl.builder() + .setTick(state().tick()) + .setRound(state().round()) + .setAvailableAt(state().availableAt()) + .setUnscheduledAt(Instant.now()) + .setError(t) + .build())); } @Override - public void executeTask(@NotNull TaskExecutionContext executionContext) { + public final void executeTask(@NotNull TaskExecutionContext executionContext) { try { debug(state().tick(), state.round(), executionContext.executedAt(), "Executing task"); task.execute(jobData(), executionContext); @@ -96,7 +125,7 @@ public void executeTask(@NotNull TaskExecutionContext executionContext) { } @Override - public void cancel() { + public final void cancel() { if (!state().completed()) { debug(state().tick(), state().round(), Instant.now(), "Canceling task"); vertx().cancelTimer(state().timerId()); @@ -108,53 +137,54 @@ public void cancel() { protected abstract boolean shouldCancel(long round); - protected void debug(long tick, long round, @NotNull Instant at, @NotNull String event) { + protected final void debug(long tick, long round, @NotNull Instant at, @NotNull String event) { if (LOGGER.isDebugEnabled()) { - LOGGER.debug("TaskExecutor[{}][{}][{}]::{}", tick, round, at, event); + LOGGER.debug("TaskExecutor[" + tick + "][" + round + "][" + at + "]::" + event); } } - protected void onReceiveTimer(long timerId) { + protected final void onReceiveTimer(long timerId) { TaskResult result; if (state().pending()) { - result = TaskResult.builder().setAvailableAt(state.timerId(timerId).markAvailable().availableAt()).build(); + result = TaskResultImpl.builder() + .setAvailableAt(state.timerId(timerId).markAvailable().availableAt()) + .build(); } else { - result = TaskResult.builder() - .setTick(state.timerId(timerId).tick()) - .setRound(state().round()) - .setAvailableAt(state().availableAt()) - .setRescheduledAt(Instant.now()) - .build(); + result = TaskResultImpl.builder() + .setTick(state.timerId(timerId).tick()) + .setRound(state().round()) + .setAvailableAt(state().availableAt()) + .setRescheduledAt(Instant.now()) + .build(); } monitor().onSchedule(result); } - protected void run(WorkerExecutor workerExecutor) { + protected final void run(WorkerExecutor workerExecutor) { final Instant triggerAt = Instant.now(); if (shouldRun(triggerAt)) { - final TaskExecutionContextImpl context = new TaskExecutionContextImpl(vertx(), state.increaseRound(), - triggerAt); - debug(state().tick(), context.round(), triggerAt, "Trigger executing task"); + TaskExecutionContextInternal ctx = new TaskExecutionContextImpl(vertx(), state.increaseRound(), triggerAt); + debug(state().tick(), ctx.round(), triggerAt, "Trigger executing task"); if (workerExecutor != null) { - workerExecutor.executeBlocking(promise -> executeTask(setupContext(promise, context)), this::onResult); + workerExecutor.executeBlocking(promise -> executeTask(setupContext(promise, ctx)), this::onResult); } else { - vertx().executeBlocking(promise -> executeTask(setupContext(promise, context)), this::onResult); + vertx().executeBlocking(promise -> executeTask(setupContext(promise, ctx)), this::onResult); } } } - protected boolean shouldRun(@NotNull Instant triggerAt) { + protected final boolean shouldRun(@NotNull Instant triggerAt) { final long tick = state.increaseTick(); if (state().completed()) { debug(tick, state().round(), triggerAt, "Execution is already completed"); } if (state().executing()) { debug(tick, state().round(), triggerAt, "Skip execution due to task is still running"); - monitor().onMisfire(TaskResult.builder() - .setAvailableAt(state().availableAt()) - .setTick(state().tick()) - .setTriggeredAt(triggerAt) - .build()); + monitor().onMisfire(TaskResultImpl.builder() + .setAvailableAt(state().availableAt()) + .setTick(state().tick()) + .setTriggeredAt(triggerAt) + .build()); } return state().idle(); } @@ -165,46 +195,46 @@ private TaskExecutionContextInternal setupContext(@NotNull Promise promi return executionContext.setup(promise, Instant.now()); } - protected void onResult(@NotNull AsyncResult asyncResult) { + protected final void onResult(@NotNull AsyncResult asyncResult) { state.markIdle(); final Instant finishedAt = Instant.now(); if (asyncResult.failed()) { - LOGGER.warn("TaskExecutor[{}][{}][{}]::{}", state().tick(), state().round(), finishedAt, - "Internal execution error", asyncResult.cause()); + LOGGER.warn("TaskExecutor[" + state().tick() + "][" + state().round() + "][" + finishedAt + "]" + + "::Internal execution error", asyncResult.cause()); } if (asyncResult.succeeded()) { final TaskExecutionContextInternal result = (TaskExecutionContextInternal) asyncResult.result(); debug(state().tick(), result.round(), finishedAt, "Handling task result"); - monitor().onEach(TaskResult.builder() - .setAvailableAt(state().availableAt()) - .setTick(state().tick()) - .setRound(result.round()) - .setTriggeredAt(result.triggeredAt()) - .setExecutedAt(result.executedAt()) - .setFinishedAt(finishedAt) - .setData(state.addData(result.round(), result.data())) - .setError(state.addError(result.round(), result.error())) - .setCompleted(state().completed()) - .build()); + monitor().onEach(TaskResultImpl.builder() + .setAvailableAt(state().availableAt()) + .setTick(state().tick()) + .setRound(result.round()) + .setTriggeredAt(result.triggeredAt()) + .setExecutedAt(result.executedAt()) + .setFinishedAt(finishedAt) + .setData(state.addData(result.round(), result.data())) + .setError(state.addError(result.round(), result.error())) + .setCompleted(state().completed()) + .build()); } if (shouldCancel(state().round())) { cancel(); } } - protected void onCompleted() { + protected final void onCompleted() { state.markCompleted(); final Instant completedAt = Instant.now(); debug(state().tick(), state().round(), completedAt, "Execution is completed"); - monitor().onCompleted(TaskResult.builder() - .setAvailableAt(state().availableAt()) - .setTick(state().tick()) - .setRound(state().round()) - .setCompleted(state().completed()) - .setCompletedAt(completedAt) - .setData(state().lastData()) - .setError(state().lastError()) - .build()); + monitor().onCompleted(TaskResultImpl.builder() + .setAvailableAt(state().availableAt()) + .setTick(state().tick()) + .setRound(state().round()) + .setCompleted(state().completed()) + .setCompletedAt(completedAt) + .setData(state().lastData()) + .setError(state().lastError()) + .build()); } } diff --git a/core/src/main/java/io/github/zero88/schedulerx/impl/AbstractTaskExecutorBuilder.java b/core/src/main/java/io/github/zero88/schedulerx/impl/AbstractTaskExecutorBuilder.java index 4395bf2..8a2504d 100644 --- a/core/src/main/java/io/github/zero88/schedulerx/impl/AbstractTaskExecutorBuilder.java +++ b/core/src/main/java/io/github/zero88/schedulerx/impl/AbstractTaskExecutorBuilder.java @@ -13,9 +13,12 @@ import io.github.zero88.schedulerx.trigger.Trigger; import io.vertx.core.Vertx; +/** + * The base task executor builder + */ @SuppressWarnings("unchecked") -abstract class AbstractTaskExecutorBuilder, - B extends AbstractTaskExecutorBuilder> +public abstract class AbstractTaskExecutorBuilder, + B extends TriggerTaskExecutorBuilder> implements TriggerTaskExecutorBuilder { private Vertx vertx; @@ -24,44 +27,48 @@ abstract class AbstractTaskExecutorBuilder { - - public @NotNull CronTaskExecutor build() { - return new CronTaskExecutorImpl(vertx(), monitor(), jobData(), task(), trigger()); - } - -} diff --git a/core/src/main/java/io/github/zero88/schedulerx/impl/IntervalTaskExecutorBuilder.java b/core/src/main/java/io/github/zero88/schedulerx/impl/IntervalTaskExecutorBuilder.java deleted file mode 100644 index 8a1c423..0000000 --- a/core/src/main/java/io/github/zero88/schedulerx/impl/IntervalTaskExecutorBuilder.java +++ /dev/null @@ -1,15 +0,0 @@ -package io.github.zero88.schedulerx.impl; - -import org.jetbrains.annotations.NotNull; - -import io.github.zero88.schedulerx.IntervalTaskExecutor; -import io.github.zero88.schedulerx.trigger.IntervalTrigger; - -public class IntervalTaskExecutorBuilder - extends AbstractTaskExecutorBuilder { - - public @NotNull IntervalTaskExecutor build() { - return new IntervalTaskExecutorImpl(vertx(), monitor(), jobData(), task(), trigger()); - } - -} diff --git a/core/src/main/java/io/github/zero88/schedulerx/impl/TaskExecutionContextImpl.java b/core/src/main/java/io/github/zero88/schedulerx/impl/TaskExecutionContextImpl.java index 07f4776..680450f 100644 --- a/core/src/main/java/io/github/zero88/schedulerx/impl/TaskExecutionContextImpl.java +++ b/core/src/main/java/io/github/zero88/schedulerx/impl/TaskExecutionContextImpl.java @@ -8,7 +8,7 @@ import io.vertx.core.Promise; import io.vertx.core.Vertx; -public final class TaskExecutionContextImpl implements TaskExecutionContextInternal { +final class TaskExecutionContextImpl implements TaskExecutionContextInternal { private final Vertx vertx; private final long round; @@ -57,13 +57,13 @@ public void forceStopExecution() { @Override public void complete(Object data) { this.data = data; - promise.tryComplete(this); + this.internalComplete(); } @Override public void fail(Throwable throwable) { this.error = throwable; - promise.tryComplete(this); + this.internalComplete(); } @Override diff --git a/core/src/main/java/io/github/zero88/schedulerx/impl/TaskExecutionContextInternal.java b/core/src/main/java/io/github/zero88/schedulerx/impl/TaskExecutionContextInternal.java index 2a607a8..0b3c591 100644 --- a/core/src/main/java/io/github/zero88/schedulerx/impl/TaskExecutionContextInternal.java +++ b/core/src/main/java/io/github/zero88/schedulerx/impl/TaskExecutionContextInternal.java @@ -8,7 +8,7 @@ import io.github.zero88.schedulerx.TaskExecutionContext; import io.vertx.core.Promise; -public interface TaskExecutionContextInternal extends TaskExecutionContext { +interface TaskExecutionContextInternal extends TaskExecutionContext { /** * Setup task execution context diff --git a/core/src/main/java/io/github/zero88/schedulerx/impl/TaskExecutorStateImpl.java b/core/src/main/java/io/github/zero88/schedulerx/impl/TaskExecutorStateImpl.java index cf1970d..2efd2bf 100644 --- a/core/src/main/java/io/github/zero88/schedulerx/impl/TaskExecutorStateImpl.java +++ b/core/src/main/java/io/github/zero88/schedulerx/impl/TaskExecutorStateImpl.java @@ -12,7 +12,7 @@ import org.jetbrains.annotations.NotNull; -public final class TaskExecutorStateImpl implements TaskExecutorStateInternal { +final class TaskExecutorStateImpl implements TaskExecutorStateInternal { private final AtomicReference availableAt = new AtomicReference<>(); private final AtomicLong tick = new AtomicLong(0); diff --git a/core/src/main/java/io/github/zero88/schedulerx/impl/TaskExecutorStateInternal.java b/core/src/main/java/io/github/zero88/schedulerx/impl/TaskExecutorStateInternal.java index 9ed3970..613046b 100644 --- a/core/src/main/java/io/github/zero88/schedulerx/impl/TaskExecutorStateInternal.java +++ b/core/src/main/java/io/github/zero88/schedulerx/impl/TaskExecutorStateInternal.java @@ -5,7 +5,7 @@ import io.github.zero88.schedulerx.TaskExecutorState; -public interface TaskExecutorStateInternal extends TaskExecutorState { +interface TaskExecutorStateInternal extends TaskExecutorState { /** * Add timer id diff --git a/core/src/main/java/io/github/zero88/schedulerx/impl/TaskResultBuilder.java b/core/src/main/java/io/github/zero88/schedulerx/impl/TaskResultBuilder.java deleted file mode 100644 index 56cf854..0000000 --- a/core/src/main/java/io/github/zero88/schedulerx/impl/TaskResultBuilder.java +++ /dev/null @@ -1,84 +0,0 @@ -package io.github.zero88.schedulerx.impl; - -import java.time.Instant; - -import io.github.zero88.schedulerx.TaskResult; - -public final class TaskResultBuilder { - - Instant unscheduledAt; - Instant rescheduledAt; - Instant availableAt; - Instant triggeredAt; - Instant executedAt; - Instant finishedAt; - Instant completedAt; - long tick; - long round; - boolean completed; - Throwable error; - Object data; - - public TaskResultBuilder setUnscheduledAt(Instant unscheduledAt) { - this.unscheduledAt = unscheduledAt; - return this; - } - - public TaskResultBuilder setRescheduledAt(Instant rescheduledAt) { - this.rescheduledAt = rescheduledAt; - return this; - } - - public TaskResultBuilder setAvailableAt(Instant availableAt) { - this.availableAt = availableAt; - return this; - } - - public TaskResultBuilder setTriggeredAt(Instant triggeredAt) { - this.triggeredAt = triggeredAt; - return this; - } - - public TaskResultBuilder setExecutedAt(Instant executedAt) { - this.executedAt = executedAt; - return this; - } - - public TaskResultBuilder setFinishedAt(Instant finishedAt) { - this.finishedAt = finishedAt; - return this; - } - - public TaskResultBuilder setCompletedAt(Instant completedAt) { - this.completedAt = completedAt; - return this; - } - - public TaskResultBuilder setTick(long tick) { - this.tick = tick; - return this; - } - - public TaskResultBuilder setRound(long round) { - this.round = round; - return this; - } - - public TaskResultBuilder setCompleted(boolean completed) { - this.completed = completed; - return this; - } - - public TaskResultBuilder setError(Throwable error) { - this.error = error; - return this; - } - - public TaskResultBuilder setData(Object data) { - this.data = data; - return this; - } - - public TaskResult build() { return new TaskResultImpl(this); } - -} diff --git a/core/src/main/java/io/github/zero88/schedulerx/impl/TaskResultImpl.java b/core/src/main/java/io/github/zero88/schedulerx/impl/TaskResultImpl.java index f1773f0..5034767 100644 --- a/core/src/main/java/io/github/zero88/schedulerx/impl/TaskResultImpl.java +++ b/core/src/main/java/io/github/zero88/schedulerx/impl/TaskResultImpl.java @@ -4,7 +4,7 @@ import io.github.zero88.schedulerx.TaskResult; -public final class TaskResultImpl implements TaskResult { +final class TaskResultImpl implements TaskResult { private final Instant unscheduledAt; private final Instant rescheduledAt; @@ -58,4 +58,95 @@ public final class TaskResultImpl implements TaskResult { public Object data() { return this.data; } + /** + * Create builder + * + * @return TaskResultBuilder + */ + static TaskResultBuilder builder() { return new TaskResultBuilder(); } + + /** + * Represents a builder that constructs {@link TaskResult} + * + * @see TaskResult + */ + static final class TaskResultBuilder { + + Instant unscheduledAt; + Instant rescheduledAt; + Instant availableAt; + Instant triggeredAt; + Instant executedAt; + Instant finishedAt; + Instant completedAt; + long tick; + long round; + boolean completed; + Throwable error; + Object data; + + public TaskResultBuilder setUnscheduledAt(Instant unscheduledAt) { + this.unscheduledAt = unscheduledAt; + return this; + } + + public TaskResultBuilder setRescheduledAt(Instant rescheduledAt) { + this.rescheduledAt = rescheduledAt; + return this; + } + + public TaskResultBuilder setAvailableAt(Instant availableAt) { + this.availableAt = availableAt; + return this; + } + + public TaskResultBuilder setTriggeredAt(Instant triggeredAt) { + this.triggeredAt = triggeredAt; + return this; + } + + public TaskResultBuilder setExecutedAt(Instant executedAt) { + this.executedAt = executedAt; + return this; + } + + public TaskResultBuilder setFinishedAt(Instant finishedAt) { + this.finishedAt = finishedAt; + return this; + } + + public TaskResultBuilder setCompletedAt(Instant completedAt) { + this.completedAt = completedAt; + return this; + } + + public TaskResultBuilder setTick(long tick) { + this.tick = tick; + return this; + } + + public TaskResultBuilder setRound(long round) { + this.round = round; + return this; + } + + public TaskResultBuilder setCompleted(boolean completed) { + this.completed = completed; + return this; + } + + public TaskResultBuilder setError(Throwable error) { + this.error = error; + return this; + } + + public TaskResultBuilder setData(Object data) { + this.data = data; + return this; + } + + public TaskResult build() { return new TaskResultImpl(this); } + + } + } diff --git a/core/src/main/java/io/github/zero88/schedulerx/impl/package-info.java b/core/src/main/java/io/github/zero88/schedulerx/impl/package-info.java new file mode 100644 index 0000000..2adbb33 --- /dev/null +++ b/core/src/main/java/io/github/zero88/schedulerx/impl/package-info.java @@ -0,0 +1,5 @@ +/** + * The scheduler.x internal implementation. + */ + +package io.github.zero88.schedulerx.impl; diff --git a/core/src/main/java/io/github/zero88/schedulerx/package-info.java b/core/src/main/java/io/github/zero88/schedulerx/package-info.java new file mode 100644 index 0000000..f3158a1 --- /dev/null +++ b/core/src/main/java/io/github/zero88/schedulerx/package-info.java @@ -0,0 +1,9 @@ +/** + * The scheduler.x core API + */ + +@ModuleGen(name = "io-zero88-schedulerx", groupPackage = "io.github.zero88.schedulerx") +package io.github.zero88.schedulerx; + +import io.vertx.codegen.annotations.ModuleGen; + diff --git a/core/src/main/java/io/github/zero88/schedulerx/trigger/CronExpression.java b/core/src/main/java/io/github/zero88/schedulerx/trigger/CronExpression.java index cf8b98f..43532ca 100644 --- a/core/src/main/java/io/github/zero88/schedulerx/trigger/CronExpression.java +++ b/core/src/main/java/io/github/zero88/schedulerx/trigger/CronExpression.java @@ -1,5 +1,3 @@ -package io.github.zero88.schedulerx.trigger; - /* * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved. * @@ -17,6 +15,8 @@ * */ +package io.github.zero88.schedulerx.trigger; + import java.io.Serializable; import java.text.ParseException; import java.util.Calendar; @@ -500,7 +500,7 @@ protected int storeExpressionVals(int pos, String s, int type) throws ParseExcep c = s.charAt(i + 3); if (c == '-') { i += 4; - sub = s.substring(i, i + 3); + sub = s.substring(i, i + 3); eval = getMonthNumber(sub) + 1; if (eval <= 0) { throw new ParseException("Invalid Month value: '" + sub + "'", i); @@ -516,7 +516,7 @@ protected int storeExpressionVals(int pos, String s, int type) throws ParseExcep c = s.charAt(i + 3); if (c == '-') { i += 4; - sub = s.substring(i, i + 3); + sub = s.substring(i, i + 3); eval = getDayOfWeekNumber(sub); if (eval < 0) { throw new ParseException("Invalid Day-of-Week value: '" + sub + "'", i); @@ -631,7 +631,7 @@ protected int storeExpressionVals(int pos, String s, int type) throws ParseExcep if (c >= '0' && c <= '9') { ValueSet vs = getValue(val, s, i); val = vs.value; - i = vs.pos; + i = vs.pos; } i = checkNext(i, s, val, type); return i; @@ -734,7 +734,7 @@ protected int checkNext(int pos, String s, int val, int type) throws ParseExcept if (c >= '0' && c <= '9') { ValueSet vs = getValue(v, s, i); end = vs.value; - i = vs.pos; + i = vs.pos; } if (i < s.length() && ((c = s.charAt(i)) == '/')) { i++; @@ -1074,7 +1074,7 @@ protected ValueSet getValue(int v, String s, int i) { } ValueSet val = new ValueSet(); - val.pos = (i < s.length()) ? i : i + 1; + val.pos = (i < s.length()) ? i : i + 1; val.value = Integer.parseInt(s1.toString()); return val; } @@ -1150,7 +1150,7 @@ public Date getTimeAfter(Date afterTime) { // get minute................................................. st = minutes.tailSet(min); if (st != null && st.size() != 0) { - t = min; + t = min; min = st.first(); } else { min = minutes.first(); @@ -1171,7 +1171,7 @@ public Date getTimeAfter(Date afterTime) { // get hour................................................... st = hours.tailSet(hr); if (st != null && st.size() != 0) { - t = hr; + t = hr; hr = st.first(); } else { hr = hours.first(); @@ -1200,20 +1200,20 @@ public Date getTimeAfter(Date afterTime) { st = daysOfMonth.tailSet(day); if (lastdayOfMonth) { if (!nearestWeekday) { - t = day; + t = day; day = getLastDayOfMonth(mon, cl.get(Calendar.YEAR)); day -= lastdayOffset; if (t > day) { mon++; if (mon > 12) { - mon = 1; + mon = 1; tmon = 3333; // ensure test of mon != tmon further below fails cl.add(Calendar.YEAR, 1); } day = 1; } } else { - t = day; + t = day; day = getLastDayOfMonth(mon, cl.get(Calendar.YEAR)); day -= lastdayOffset; @@ -1250,7 +1250,7 @@ public Date getTimeAfter(Date afterTime) { } } } else if (nearestWeekday) { - t = day; + t = day; day = daysOfMonth.first(); java.util.Calendar tcal = java.util.Calendar.getInstance(getTimeZone()); @@ -1285,7 +1285,7 @@ public Date getTimeAfter(Date afterTime) { mon++; } } else if (st != null && st.size() != 0) { - t = day; + t = day; day = st.first(); // make sure we don't over-run a short month, such as february int lastDay = getLastDayOfMonth(mon, cl.get(Calendar.YEAR)); @@ -1453,7 +1453,7 @@ public Date getTimeAfter(Date afterTime) { // get month................................................... st = months.tailSet(mon); if (st != null && st.size() != 0) { - t = mon; + t = mon; mon = st.first(); } else { mon = months.first(); @@ -1475,12 +1475,12 @@ public Date getTimeAfter(Date afterTime) { // 1-based year = cl.get(Calendar.YEAR); - t = -1; + t = -1; // get year................................................... st = years.tailSet(year); if (st != null && st.size() != 0) { - t = year; + t = year; year = st.first(); } else { return null; // ran out of years... diff --git a/core/src/main/java/io/github/zero88/schedulerx/trigger/CronTrigger.java b/core/src/main/java/io/github/zero88/schedulerx/trigger/CronTrigger.java index 0bd94b1..8d617b7 100644 --- a/core/src/main/java/io/github/zero88/schedulerx/trigger/CronTrigger.java +++ b/core/src/main/java/io/github/zero88/schedulerx/trigger/CronTrigger.java @@ -93,6 +93,9 @@ public String toString() { return "CronTrigger(expression=" + expression + ", timeZone=" + timeZone + ')'; } + /** + * Represents a builder that constructs {@link CronTrigger} + */ @JsonPOJOBuilder(withPrefix = "") public static class CronTriggerBuilder { diff --git a/core/src/main/java/io/github/zero88/schedulerx/trigger/CronTriggerExecutor.java b/core/src/main/java/io/github/zero88/schedulerx/trigger/CronTriggerExecutor.java new file mode 100644 index 0000000..b9510fb --- /dev/null +++ b/core/src/main/java/io/github/zero88/schedulerx/trigger/CronTriggerExecutor.java @@ -0,0 +1,24 @@ +package io.github.zero88.schedulerx.trigger; + +import org.jetbrains.annotations.NotNull; + +import io.github.zero88.schedulerx.TriggerTaskExecutor; +import io.vertx.codegen.annotations.GenIgnore; +import io.vertx.codegen.annotations.VertxGen; + +/** + * Represents for the task executor has an execution loop based on the timer of cron expressions. + * + * @see CronTrigger + * @since 2.0.0 + */ +@VertxGen +public interface CronTriggerExecutor extends TriggerTaskExecutor { + + static CronTriggerExecutorBuilder builder() { return new CronTriggerExecutorImpl.CronTriggerExecutorBuilderImpl(); } + + @Override + @GenIgnore(GenIgnore.PERMITTED_TYPE) + @NotNull CronTrigger trigger(); + +} diff --git a/core/src/main/java/io/github/zero88/schedulerx/trigger/CronTriggerExecutorBuilder.java b/core/src/main/java/io/github/zero88/schedulerx/trigger/CronTriggerExecutorBuilder.java new file mode 100644 index 0000000..cd84b1d --- /dev/null +++ b/core/src/main/java/io/github/zero88/schedulerx/trigger/CronTriggerExecutorBuilder.java @@ -0,0 +1,47 @@ +package io.github.zero88.schedulerx.trigger; + +import org.jetbrains.annotations.NotNull; + +import io.github.zero88.schedulerx.JobData; +import io.github.zero88.schedulerx.Task; +import io.github.zero88.schedulerx.TaskExecutorMonitor; +import io.github.zero88.schedulerx.TriggerTaskExecutorBuilder; +import io.vertx.codegen.annotations.Fluent; +import io.vertx.codegen.annotations.GenIgnore; +import io.vertx.codegen.annotations.VertxGen; +import io.vertx.core.Vertx; + +/** + * Represents a builder that constructs {@link CronTriggerExecutor} + * + * @since 2.0.0 + */ +@VertxGen +public interface CronTriggerExecutorBuilder + extends TriggerTaskExecutorBuilder { + + @GenIgnore(GenIgnore.PERMITTED_TYPE) + @NotNull CronTrigger trigger(); + + @Fluent + @NotNull CronTriggerExecutorBuilder setVertx(@NotNull Vertx vertx); + + @Fluent + @GenIgnore(GenIgnore.PERMITTED_TYPE) + @NotNull CronTriggerExecutorBuilder setTask(@NotNull Task task); + + @Fluent + @GenIgnore(GenIgnore.PERMITTED_TYPE) + @NotNull CronTriggerExecutorBuilder setTrigger(@NotNull CronTrigger trigger); + + @Fluent + @GenIgnore(GenIgnore.PERMITTED_TYPE) + @NotNull CronTriggerExecutorBuilder setJobData(@NotNull JobData jobData); + + @Fluent + @GenIgnore(GenIgnore.PERMITTED_TYPE) + @NotNull CronTriggerExecutorBuilder setMonitor(@NotNull TaskExecutorMonitor monitor); + + @NotNull CronTriggerExecutor build(); + +} diff --git a/core/src/main/java/io/github/zero88/schedulerx/impl/CronTaskExecutorImpl.java b/core/src/main/java/io/github/zero88/schedulerx/trigger/CronTriggerExecutorImpl.java similarity index 53% rename from core/src/main/java/io/github/zero88/schedulerx/impl/CronTaskExecutorImpl.java rename to core/src/main/java/io/github/zero88/schedulerx/trigger/CronTriggerExecutorImpl.java index 19585d7..f612cfa 100644 --- a/core/src/main/java/io/github/zero88/schedulerx/impl/CronTaskExecutorImpl.java +++ b/core/src/main/java/io/github/zero88/schedulerx/trigger/CronTriggerExecutorImpl.java @@ -1,23 +1,23 @@ -package io.github.zero88.schedulerx.impl; +package io.github.zero88.schedulerx.trigger; import java.time.Instant; import org.jetbrains.annotations.NotNull; -import io.github.zero88.schedulerx.CronTaskExecutor; import io.github.zero88.schedulerx.JobData; import io.github.zero88.schedulerx.Task; import io.github.zero88.schedulerx.TaskExecutorMonitor; -import io.github.zero88.schedulerx.trigger.CronTrigger; +import io.github.zero88.schedulerx.impl.AbstractTaskExecutor; +import io.github.zero88.schedulerx.impl.AbstractTaskExecutorBuilder; import io.vertx.core.Future; import io.vertx.core.Promise; import io.vertx.core.Vertx; import io.vertx.core.WorkerExecutor; -final class CronTaskExecutorImpl extends AbstractTaskExecutor implements CronTaskExecutor { +final class CronTriggerExecutorImpl extends AbstractTaskExecutor implements CronTriggerExecutor { - CronTaskExecutorImpl(@NotNull Vertx vertx, @NotNull TaskExecutorMonitor monitor, @NotNull JobData jobData, - @NotNull Task task, @NotNull CronTrigger trigger) { + CronTriggerExecutorImpl(@NotNull Vertx vertx, @NotNull TaskExecutorMonitor monitor, @NotNull JobData jobData, + @NotNull Task task, @NotNull CronTrigger trigger) { super(vertx, monitor, jobData, task, trigger); } @@ -40,4 +40,14 @@ protected boolean shouldCancel(long round) { return false; } + static final class CronTriggerExecutorBuilderImpl + extends AbstractTaskExecutorBuilder + implements CronTriggerExecutorBuilder { + + public @NotNull CronTriggerExecutor build() { + return new CronTriggerExecutorImpl(vertx(), monitor(), jobData(), task(), trigger()); + } + + } + } diff --git a/core/src/main/java/io/github/zero88/schedulerx/trigger/IntervalTrigger.java b/core/src/main/java/io/github/zero88/schedulerx/trigger/IntervalTrigger.java index 58ec07e..f5d983d 100644 --- a/core/src/main/java/io/github/zero88/schedulerx/trigger/IntervalTrigger.java +++ b/core/src/main/java/io/github/zero88/schedulerx/trigger/IntervalTrigger.java @@ -137,6 +137,9 @@ static void validate(long number, boolean allowZero, boolean allowIndefinitely, throw new IllegalArgumentException("Invalid " + msg + " value"); } + /** + * Represents a builder that constructs {@link IntervalTrigger} + */ @JsonPOJOBuilder(withPrefix = "") public static class IntervalTriggerBuilder { diff --git a/core/src/main/java/io/github/zero88/schedulerx/trigger/IntervalTriggerExecutor.java b/core/src/main/java/io/github/zero88/schedulerx/trigger/IntervalTriggerExecutor.java new file mode 100644 index 0000000..9633c3f --- /dev/null +++ b/core/src/main/java/io/github/zero88/schedulerx/trigger/IntervalTriggerExecutor.java @@ -0,0 +1,24 @@ +package io.github.zero88.schedulerx.trigger; + +import org.jetbrains.annotations.NotNull; + +import io.github.zero88.schedulerx.TriggerTaskExecutor; +import io.vertx.codegen.annotations.GenIgnore; +import io.vertx.codegen.annotations.VertxGen; + +/** + * Represents for the task executor has an execution loop based on interval. + * + * @see IntervalTrigger + * @since 2.0.0 + */ +@VertxGen +public interface IntervalTriggerExecutor extends TriggerTaskExecutor { + + static IntervalTriggerExecutorBuilder builder() { return new IntervalTriggerExecutorImpl.IntervalTriggerExecutorBuilderImpl(); } + + @Override + @GenIgnore(GenIgnore.PERMITTED_TYPE) + @NotNull IntervalTrigger trigger(); + +} diff --git a/core/src/main/java/io/github/zero88/schedulerx/trigger/IntervalTriggerExecutorBuilder.java b/core/src/main/java/io/github/zero88/schedulerx/trigger/IntervalTriggerExecutorBuilder.java new file mode 100644 index 0000000..c642525 --- /dev/null +++ b/core/src/main/java/io/github/zero88/schedulerx/trigger/IntervalTriggerExecutorBuilder.java @@ -0,0 +1,48 @@ +package io.github.zero88.schedulerx.trigger; + +import org.jetbrains.annotations.NotNull; + +import io.github.zero88.schedulerx.JobData; +import io.github.zero88.schedulerx.Task; +import io.github.zero88.schedulerx.TaskExecutorMonitor; +import io.github.zero88.schedulerx.TriggerTaskExecutorBuilder; +import io.vertx.codegen.annotations.Fluent; +import io.vertx.codegen.annotations.GenIgnore; +import io.vertx.codegen.annotations.VertxGen; +import io.vertx.core.Vertx; + +/** + * Represents a builder that constructs {@link IntervalTriggerExecutor} + * + * @since 2.0.0 + */ +@VertxGen +public interface IntervalTriggerExecutorBuilder + extends TriggerTaskExecutorBuilder { + + @GenIgnore(GenIgnore.PERMITTED_TYPE) + @NotNull IntervalTrigger trigger(); + + @Fluent + @GenIgnore(GenIgnore.PERMITTED_TYPE) + @NotNull IntervalTriggerExecutorBuilder setVertx(@NotNull Vertx vertx); + + @Fluent + @GenIgnore(GenIgnore.PERMITTED_TYPE) + @NotNull IntervalTriggerExecutorBuilder setTask(@NotNull Task task); + + @Fluent + @GenIgnore(GenIgnore.PERMITTED_TYPE) + @NotNull IntervalTriggerExecutorBuilder setTrigger(@NotNull IntervalTrigger trigger); + + @Fluent + @GenIgnore(GenIgnore.PERMITTED_TYPE) + @NotNull IntervalTriggerExecutorBuilder setJobData(@NotNull JobData jobData); + + @Fluent + @GenIgnore(GenIgnore.PERMITTED_TYPE) + @NotNull IntervalTriggerExecutorBuilder setMonitor(@NotNull TaskExecutorMonitor monitor); + + @NotNull IntervalTriggerExecutor build(); + +} diff --git a/core/src/main/java/io/github/zero88/schedulerx/impl/IntervalTaskExecutorImpl.java b/core/src/main/java/io/github/zero88/schedulerx/trigger/IntervalTriggerExecutorImpl.java similarity index 51% rename from core/src/main/java/io/github/zero88/schedulerx/impl/IntervalTaskExecutorImpl.java rename to core/src/main/java/io/github/zero88/schedulerx/trigger/IntervalTriggerExecutorImpl.java index eedba1d..19d6d84 100644 --- a/core/src/main/java/io/github/zero88/schedulerx/impl/IntervalTaskExecutorImpl.java +++ b/core/src/main/java/io/github/zero88/schedulerx/trigger/IntervalTriggerExecutorImpl.java @@ -1,36 +1,36 @@ -package io.github.zero88.schedulerx.impl; +package io.github.zero88.schedulerx.trigger; import java.time.Instant; import java.util.function.LongSupplier; import org.jetbrains.annotations.NotNull; -import io.github.zero88.schedulerx.IntervalTaskExecutor; import io.github.zero88.schedulerx.JobData; import io.github.zero88.schedulerx.Task; import io.github.zero88.schedulerx.TaskExecutorMonitor; -import io.github.zero88.schedulerx.trigger.IntervalTrigger; +import io.github.zero88.schedulerx.impl.AbstractTaskExecutor; +import io.github.zero88.schedulerx.impl.AbstractTaskExecutorBuilder; import io.vertx.core.Future; import io.vertx.core.Promise; import io.vertx.core.Vertx; import io.vertx.core.WorkerExecutor; -final class IntervalTaskExecutorImpl extends AbstractTaskExecutor implements IntervalTaskExecutor { +final class IntervalTriggerExecutorImpl extends AbstractTaskExecutor + implements IntervalTriggerExecutor { - IntervalTaskExecutorImpl(@NotNull Vertx vertx, @NotNull TaskExecutorMonitor monitor, @NotNull JobData jobData, - @NotNull Task task, @NotNull IntervalTrigger trigger) { + IntervalTriggerExecutorImpl(@NotNull Vertx vertx, @NotNull TaskExecutorMonitor monitor, @NotNull JobData jobData, + @NotNull Task task, @NotNull IntervalTrigger trigger) { super(vertx, monitor, jobData, task, trigger); } protected @NotNull Future addTimer(@NotNull Promise promise, WorkerExecutor workerExecutor) { try { - final IntervalTrigger trigger = trigger(); - LongSupplier supplier = () -> vertx().setPeriodic(trigger.intervalInMilliseconds(), + LongSupplier supplier = () -> vertx().setPeriodic(trigger().intervalInMilliseconds(), timerId -> run(workerExecutor)); - if (trigger.noDelay()) { + if (trigger().noDelay()) { promise.complete(supplier.getAsLong()); } else { - final long delay = trigger.delayInMilliseconds(); + final long delay = trigger().delayInMilliseconds(); debug(-1, -1, Instant.now(), "delay [" + delay + "ms] then register task in schedule"); vertx().setTimer(delay, ignore -> promise.complete(supplier.getAsLong())); } @@ -42,8 +42,17 @@ final class IntervalTaskExecutorImpl extends AbstractTaskExecutor= trigger.getRepeat(); + return trigger().noRepeatIndefinitely() && round >= trigger().getRepeat(); + } + + static final class IntervalTriggerExecutorBuilderImpl + extends AbstractTaskExecutorBuilder + implements IntervalTriggerExecutorBuilder { + + public @NotNull IntervalTriggerExecutor build() { + return new IntervalTriggerExecutorImpl(vertx(), monitor(), jobData(), task(), trigger()); + } + } } diff --git a/core/src/main/java/io/github/zero88/schedulerx/trigger/package-info.java b/core/src/main/java/io/github/zero88/schedulerx/trigger/package-info.java new file mode 100644 index 0000000..7043b54 --- /dev/null +++ b/core/src/main/java/io/github/zero88/schedulerx/trigger/package-info.java @@ -0,0 +1,10 @@ +/** + * Provides the classes and interfaces to define the trigger and its executor. + * + * @since 2.0.0 + */ + +@ModuleGen(name = "io-zero88-schedulerx", groupPackage = "io.github.zero88.schedulerx") +package io.github.zero88.schedulerx.trigger; + +import io.vertx.codegen.annotations.ModuleGen; diff --git a/core/src/test/java/io/github/zero88/schedulerx/custom/HttpClientTask.java b/core/src/test/java/io/github/zero88/schedulerx/custom/HttpClientTask.java index 60823d1..4a5cc98 100644 --- a/core/src/test/java/io/github/zero88/schedulerx/custom/HttpClientTask.java +++ b/core/src/test/java/io/github/zero88/schedulerx/custom/HttpClientTask.java @@ -1,16 +1,16 @@ package io.github.zero88.schedulerx.custom; +import org.jetbrains.annotations.NotNull; + import io.github.zero88.schedulerx.JobData; import io.github.zero88.schedulerx.Task; import io.github.zero88.schedulerx.TaskExecutionContext; +import io.vertx.core.Future; import io.vertx.core.Vertx; import io.vertx.core.http.HttpClientRequest; -import io.vertx.core.http.HttpClientResponse; import io.vertx.core.http.HttpMethod; import io.vertx.core.json.JsonObject; -import org.jetbrains.annotations.NotNull; - public class HttpClientTask implements Task { @Override @@ -20,30 +20,18 @@ public boolean isAsync() { @Override public void execute(@NotNull JobData jobData, @NotNull TaskExecutionContext executionContext) { - final Vertx vertx = executionContext.vertx(); + doExecute(executionContext.vertx(), jobData).onSuccess(executionContext::complete) + .onFailure(executionContext::fail); + } + + private Future doExecute(Vertx vertx, @NotNull JobData jobData) { JsonObject url = (JsonObject) jobData.get(); - vertx.createHttpClient().request(HttpMethod.GET, url.getString("host"), url.getString("path"), ar1 -> { - if (ar1.succeeded()) { - HttpClientRequest request = ar1.result(); - request.send(ar2 -> { - if (ar2.succeeded()) { - HttpClientResponse response = ar2.result(); - response.body(ar3 -> { - if (ar3.succeeded()) { - executionContext.complete(new JsonObject().put("status", response.statusCode()) - .put("response", ar3.result().toJson())); - } else { - executionContext.fail(ar3.cause()); - } - }); - } else { - executionContext.fail(ar2.cause()); - } - }); - } else { - executionContext.fail(ar1.cause()); - } - }); + return vertx.createHttpClient() + .request(HttpMethod.GET, url.getString("host"), url.getString("path")) + .flatMap(HttpClientRequest::send) + .flatMap(response -> response.body() + .map(ar3 -> new JsonObject().put("status", response.statusCode()) + .put("response", ar3.toJson()))); } } diff --git a/core/src/test/java/io/github/zero88/schedulerx/custom/HttpClientTaskTest.java b/core/src/test/java/io/github/zero88/schedulerx/custom/HttpClientTaskTest.java index dd96663..e911192 100644 --- a/core/src/test/java/io/github/zero88/schedulerx/custom/HttpClientTaskTest.java +++ b/core/src/test/java/io/github/zero88/schedulerx/custom/HttpClientTaskTest.java @@ -6,9 +6,9 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import io.github.zero88.schedulerx.IntervalTaskExecutor; import io.github.zero88.schedulerx.TaskExecutorAsserter; import io.github.zero88.schedulerx.TaskResult; +import io.github.zero88.schedulerx.trigger.IntervalTriggerExecutor; import io.github.zero88.schedulerx.trigger.IntervalTrigger; import io.vertx.core.Vertx; import io.vertx.core.json.JsonObject; @@ -32,17 +32,17 @@ void test_http_task(Vertx vertx, VertxTestContext testContext) { Assertions.assertEquals("http://" + host + path, response.getJsonObject("response").getString("url")); }; final TaskExecutorAsserter monitor = TaskExecutorAsserter.builder() - .testContext(testContext) - .each(verification) + .setTestContext(testContext) + .setEach(verification) .build(); - IntervalTaskExecutor.builder() - .setVertx(vertx) - .setTrigger(IntervalTrigger.builder().interval(3).repeat(2).build()) - .setTask(new HttpClientTask()) - .setMonitor(monitor) - .setJobData(() -> new JsonObject().put("host", host).put("path", path)) - .build() - .start(); + IntervalTriggerExecutor.builder() + .setVertx(vertx) + .setTrigger(IntervalTrigger.builder().interval(3).repeat(2).build()) + .setTask(new HttpClientTask()) + .setMonitor(monitor) + .setJobData(() -> new JsonObject().put("host", host).put("path", path)) + .build() + .start(); } } diff --git a/core/src/test/java/io/github/zero88/schedulerx/CronTaskExecutorTest.java b/core/src/test/java/io/github/zero88/schedulerx/trigger/CronTriggerExecutorTest.java similarity index 57% rename from core/src/test/java/io/github/zero88/schedulerx/CronTaskExecutorTest.java rename to core/src/test/java/io/github/zero88/schedulerx/trigger/CronTriggerExecutorTest.java index 42a387e..4df7e03 100644 --- a/core/src/test/java/io/github/zero88/schedulerx/CronTaskExecutorTest.java +++ b/core/src/test/java/io/github/zero88/schedulerx/trigger/CronTriggerExecutorTest.java @@ -1,4 +1,4 @@ -package io.github.zero88.schedulerx; +package io.github.zero88.schedulerx.trigger; import java.util.function.Consumer; @@ -6,25 +6,26 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import io.github.zero88.schedulerx.trigger.CronTrigger; +import io.github.zero88.schedulerx.TaskExecutorAsserter; +import io.github.zero88.schedulerx.TaskResult; import io.vertx.core.Vertx; import io.vertx.junit5.Checkpoint; import io.vertx.junit5.VertxExtension; import io.vertx.junit5.VertxTestContext; @ExtendWith(VertxExtension.class) -class CronTaskExecutorTest { +class CronTriggerExecutorTest { @Test void test_unable_schedule_due_to_initial(Vertx vertx, VertxTestContext testContext) { final Checkpoint checkpoint = testContext.checkpoint(2); - CronTaskExecutor.builder() - .setVertx(vertx) - .setTrigger(CronTrigger.builder().expression("0/").build()) - .setTask((jobData, ctx) -> { }) - .setMonitor(TaskExecutorAsserter.unableScheduleAsserter(testContext, checkpoint)) - .build() - .start(); + CronTriggerExecutor.builder() + .setVertx(vertx) + .setTrigger(CronTrigger.builder().expression("0/").build()) + .setTask((jobData, ctx) -> { }) + .setMonitor(TaskExecutorAsserter.unableScheduleAsserter(testContext, checkpoint)) + .build() + .start(); } @Test @@ -45,22 +46,22 @@ void test_run_task_by_cron(Vertx vertx, VertxTestContext testContext) { Assertions.assertTrue(result.isCompleted()); Assertions.assertFalse(result.isError()); }; - CronTaskExecutor.builder() - .setVertx(vertx) - .setTrigger(CronTrigger.builder().expression("0/5 * * ? * * *").build()) - .setTask((jobData, ctx) -> { + CronTriggerExecutor.builder() + .setVertx(vertx) + .setTrigger(CronTrigger.builder().expression("0/5 * * ? * * *").build()) + .setTask((jobData, ctx) -> { checkpoint.flag(); if (ctx.round() == 2) { ctx.forceStopExecution(); } }) - .setMonitor(TaskExecutorAsserter.builder() - .testContext(testContext) - .schedule(schedule) - .completed(completed) + .setMonitor(TaskExecutorAsserter.builder() + .setTestContext(testContext) + .setSchedule(schedule) + .setCompleted(completed) .build()) - .build() - .start(); + .build() + .start(); } } diff --git a/core/src/test/java/io/github/zero88/schedulerx/IntervalTaskExecutorTest.java b/core/src/test/java/io/github/zero88/schedulerx/trigger/IntervalTriggerExecutorTest.java similarity index 55% rename from core/src/test/java/io/github/zero88/schedulerx/IntervalTaskExecutorTest.java rename to core/src/test/java/io/github/zero88/schedulerx/trigger/IntervalTriggerExecutorTest.java index 4478d39..cd40f69 100644 --- a/core/src/test/java/io/github/zero88/schedulerx/IntervalTaskExecutorTest.java +++ b/core/src/test/java/io/github/zero88/schedulerx/trigger/IntervalTriggerExecutorTest.java @@ -1,4 +1,4 @@ -package io.github.zero88.schedulerx; +package io.github.zero88.schedulerx.trigger; import java.util.function.Consumer; @@ -6,7 +6,9 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import io.github.zero88.schedulerx.trigger.IntervalTrigger; +import io.github.zero88.schedulerx.Task; +import io.github.zero88.schedulerx.TaskExecutorAsserter; +import io.github.zero88.schedulerx.TaskResult; import io.vertx.core.Vertx; import io.vertx.core.WorkerExecutor; import io.vertx.junit5.Checkpoint; @@ -14,7 +16,7 @@ import io.vertx.junit5.VertxTestContext; @ExtendWith(VertxExtension.class) -class IntervalTaskExecutorTest { +class IntervalTriggerExecutorTest { static void sleep(int millis, VertxTestContext testContext) { try { @@ -27,25 +29,25 @@ static void sleep(int millis, VertxTestContext testContext) { @Test void test_run_task_unable_schedule_due_to_interval(Vertx vertx, VertxTestContext testContext) { final Checkpoint checkpoint = testContext.checkpoint(2); - IntervalTaskExecutor.builder() - .setVertx(vertx) - .setTrigger(IntervalTrigger.builder().interval(-1).build()) - .setTask((jobData, ctx) -> { }) - .setMonitor(TaskExecutorAsserter.unableScheduleAsserter(testContext, checkpoint)) - .build() - .start(); + IntervalTriggerExecutor.builder() + .setVertx(vertx) + .setTrigger(IntervalTrigger.builder().interval(-1).build()) + .setTask((jobData, ctx) -> { }) + .setMonitor(TaskExecutorAsserter.unableScheduleAsserter(testContext, checkpoint)) + .build() + .start(); } @Test void test_run_task_unable_schedule_due_to_initial(Vertx vertx, VertxTestContext testContext) { final Checkpoint checkpoint = testContext.checkpoint(2); - IntervalTaskExecutor.builder() - .setVertx(vertx) - .setTrigger(IntervalTrigger.builder().initialDelay(-1).build()) - .setTask((jobData, ctx) -> { }) - .setMonitor(TaskExecutorAsserter.unableScheduleAsserter(testContext, checkpoint)) - .build() - .start(); + IntervalTriggerExecutor.builder() + .setVertx(vertx) + .setTrigger(IntervalTrigger.builder().initialDelay(-1).build()) + .setTask((jobData, ctx) -> { }) + .setMonitor(TaskExecutorAsserter.unableScheduleAsserter(testContext, checkpoint)) + .build() + .start(); } @Test @@ -65,14 +67,17 @@ void test_run_task_after_delay(Vertx vertx, VertxTestContext ctx) { Assertions.assertFalse(result.isError()); ctx.completeNow(); }; - IntervalTaskExecutor.builder() - .setVertx(vertx) - .setTrigger(IntervalTrigger.builder().initialDelay(2).interval(2).repeat(2).build()) - .setTask((jobData, context) -> { }) - .setMonitor( - TaskExecutorAsserter.builder().testContext(ctx).schedule(s).completed(c).build()) - .build() - .start(worker); + IntervalTriggerExecutor.builder() + .setVertx(vertx) + .setTrigger(IntervalTrigger.builder().initialDelay(2).interval(2).repeat(2).build()) + .setTask((jobData, context) -> { }) + .setMonitor(TaskExecutorAsserter.builder() + .setTestContext(ctx) + .setSchedule(s) + .setCompleted(c) + .build()) + .build() + .start(worker); } @Test @@ -85,16 +90,17 @@ void test_run_blocking_task_in_the_end(Vertx vertx, VertxTestContext testContext Assertions.assertTrue(result.isCompleted()); Assertions.assertFalse(result.isError()); }; - IntervalTaskExecutor.builder() - .setVertx(vertx) - .setTrigger(IntervalTrigger.builder().interval(2).repeat(3).build()) - .setTask((jobData, ctx) -> { + IntervalTriggerExecutor.builder() + .setVertx(vertx) + .setTrigger(IntervalTrigger.builder().interval(2).repeat(3).build()) + .setTask((jobData, ctx) -> { sleep(3000, testContext); checkpoint.flag(); }) - .setMonitor(TaskExecutorAsserter.builder().testContext(testContext).completed(c).build()) - .build() - .start(worker); + .setMonitor( + TaskExecutorAsserter.builder().setTestContext(testContext).setCompleted(c).build()) + .build() + .start(worker); } @Test @@ -131,14 +137,17 @@ void test_cancel_task_in_condition(Vertx vertx, VertxTestContext context) { Assertions.assertTrue(result.isCompleted()); Assertions.assertFalse(result.isError()); }; - IntervalTaskExecutor.builder() - .setVertx(vertx) - .setTrigger(IntervalTrigger.builder().interval(1).repeat(10).build()) - .setTask(task) - .setMonitor( - TaskExecutorAsserter.builder().testContext(context).each(e).completed(c).build()) - .build() - .start(); + IntervalTriggerExecutor.builder() + .setVertx(vertx) + .setTrigger(IntervalTrigger.builder().interval(1).repeat(10).build()) + .setTask(task) + .setMonitor(TaskExecutorAsserter.builder() + .setTestContext(context) + .setEach(e) + .setCompleted(c) + .build()) + .build() + .start(); } } diff --git a/core/src/testFixtures/java/io/github/zero88/schedulerx/TaskExecutorAsserter.java b/core/src/testFixtures/java/io/github/zero88/schedulerx/TaskExecutorAsserter.java index fde9f2c..7f6b8e1 100644 --- a/core/src/testFixtures/java/io/github/zero88/schedulerx/TaskExecutorAsserter.java +++ b/core/src/testFixtures/java/io/github/zero88/schedulerx/TaskExecutorAsserter.java @@ -1,28 +1,39 @@ package io.github.zero88.schedulerx; import java.util.Objects; +import java.util.Optional; import java.util.function.Consumer; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.junit.jupiter.api.Assertions; import io.vertx.junit5.Checkpoint; import io.vertx.junit5.VertxTestContext; -public class TaskExecutorAsserter implements TaskExecutorLogMonitor { +/** + * Represents for the executor monitor that able to do test assert. + * + * @see TaskExecutorMonitor + * @since 1.0.0 + */ +public final class TaskExecutorAsserter implements TaskExecutorMonitor { @NotNull private final VertxTestContext testContext; + @NotNull + private final TaskExecutorMonitor logMonitor; private final Consumer unableSchedule; private final Consumer schedule; private final Consumer misfire; private final Consumer each; private final Consumer completed; - TaskExecutorAsserter(@NotNull VertxTestContext testContext, Consumer unableSchedule, - Consumer schedule, Consumer misfire, Consumer each, - Consumer completed) { + TaskExecutorAsserter(@NotNull VertxTestContext testContext, @Nullable TaskExecutorMonitor logMonitor, + Consumer unableSchedule, Consumer schedule, + Consumer misfire, Consumer each, Consumer completed) { this.testContext = Objects.requireNonNull(testContext, "Vertx Test context is required"); + this.logMonitor = Optional.ofNullable(logMonitor).orElse(TaskExecutorLogMonitor.LOG_MONITOR); this.unableSchedule = unableSchedule; this.schedule = schedule; this.misfire = misfire; @@ -34,31 +45,31 @@ public class TaskExecutorAsserter implements TaskExecutorLogMonitor { @Override public void onUnableSchedule(@NotNull TaskResult result) { - TaskExecutorLogMonitor.super.onUnableSchedule(result); + logMonitor.onUnableSchedule(result); verify(result, unableSchedule); } @Override public void onSchedule(@NotNull TaskResult result) { - TaskExecutorLogMonitor.super.onSchedule(result); + logMonitor.onSchedule(result); verify(result, schedule); } @Override public void onMisfire(@NotNull TaskResult result) { - TaskExecutorLogMonitor.super.onMisfire(result); + logMonitor.onMisfire(result); verify(result, misfire); } @Override public void onEach(@NotNull TaskResult result) { - TaskExecutorLogMonitor.super.onEach(result); + logMonitor.onEach(result); verify(result, each); } @Override public void onCompleted(@NotNull TaskResult result) { - TaskExecutorLogMonitor.super.onCompleted(result); + logMonitor.onCompleted(result); verify(result, r -> { completed.accept(r); testContext.completeNow(); @@ -75,8 +86,9 @@ private void verify(@NotNull TaskResult result, Consumer verificatio } } - static TaskExecutorMonitor unableScheduleAsserter(VertxTestContext testContext, Checkpoint checkpoint) { - return TaskExecutorAsserter.builder().testContext(testContext).unableSchedule(result -> { + @SuppressWarnings("java:S5960") + public static TaskExecutorMonitor unableScheduleAsserter(VertxTestContext testContext, Checkpoint checkpoint) { + return TaskExecutorAsserter.builder().setTestContext(testContext).setUnableSchedule(result -> { checkpoint.flag(); Assertions.assertNotNull(result.unscheduledAt()); Assertions.assertNull(result.availableAt()); @@ -88,45 +100,111 @@ static TaskExecutorMonitor unableScheduleAsserter(VertxTestContext testContext, public static class TaskExecutorAsserterBuilder { private VertxTestContext testContext; + private TaskExecutorMonitor logMonitor; private Consumer unableSchedule; private Consumer schedule; private Consumer misfire; private Consumer each; private Consumer completed; - public TaskExecutorAsserterBuilder testContext(@NotNull VertxTestContext testContext) { + /** + * Set Vertx test context + * + * @param testContext test context + * @return this for fluent API + * @see VertxTestContext + */ + public TaskExecutorAsserterBuilder setTestContext(@NotNull VertxTestContext testContext) { this.testContext = testContext; return this; } - public TaskExecutorAsserterBuilder unableSchedule(Consumer unableSchedule) { + /** + * Set log monitor + * + * @param logMonitor a log monitor + * @return this for fluent API + * @see TaskExecutorMonitor + * @since 2.0.0 + */ + public TaskExecutorAsserterBuilder setLogMonitor(TaskExecutorMonitor logMonitor) { + this.logMonitor = logMonitor; + return this; + } + + /** + * Set a task result verification when unable to schedule task + * + * @param unableSchedule a verification when unable to schedule task + * @return this for fluent API + * @see TaskResult + * @see TaskExecutorMonitor#onUnableSchedule(TaskResult) + */ + public TaskExecutorAsserterBuilder setUnableSchedule(Consumer unableSchedule) { this.unableSchedule = unableSchedule; return this; } - public TaskExecutorAsserterBuilder schedule(Consumer schedule) { + /** + * Set a task result verification when schedule task + * + * @param schedule a verification when schedule task + * @return this for fluent API + * @see TaskResult + * @see TaskExecutorMonitor#onSchedule(TaskResult) + */ + public TaskExecutorAsserterBuilder setSchedule(Consumer schedule) { this.schedule = schedule; return this; } - public TaskExecutorAsserterBuilder misfire(Consumer misfire) { + /** + * Set a task result verification when misfire task + * + * @param misfire a verification when misfire task + * @return this for fluent API + * @see TaskResult + * @see TaskExecutorMonitor#onMisfire(TaskResult) + */ + public TaskExecutorAsserterBuilder setMisfire(Consumer misfire) { this.misfire = misfire; return this; } - public TaskExecutorAsserterBuilder each(Consumer each) { + /** + * Set a task result verification when each round is finished + * + * @param each a verification when each round is finished of schedule + * @return this for fluent API + * @see TaskResult + * @see TaskExecutorMonitor#onEach(TaskResult) + */ + public TaskExecutorAsserterBuilder setEach(Consumer each) { this.each = each; return this; } - public TaskExecutorAsserterBuilder completed(Consumer completed) { + /** + * Set a task result verification when execution is completed + * + * @param completed a verification when execution is completed + * @return this for fluent API + * @see TaskResult + * @see TaskExecutorMonitor#onCompleted(TaskResult) + */ + public TaskExecutorAsserterBuilder setCompleted(Consumer completed) { this.completed = completed; return this; } + /** + * Build an asserter + * + * @return TaskExecutorAsserter + */ public TaskExecutorAsserter build() { - return new TaskExecutorAsserter(this.testContext, this.unableSchedule, this.schedule, this.misfire, - this.each, this.completed); + return new TaskExecutorAsserter(testContext, logMonitor, unableSchedule, schedule, misfire, each, + completed); } }