All Downloads are FREE. Search and download functionalities are using the official Maven repository.

fi.evolver.basics.spring.timer.entity.ScheduledTask Maven / Gradle / Ivy

package fi.evolver.basics.spring.timer.entity;

import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import org.springframework.scheduling.support.CronExpression;

import com.fasterxml.jackson.annotation.JsonIgnore;

import jakarta.persistence.*;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;

@Entity
@Table(name="scheduled_task")
public class ScheduledTask {

	public enum State { WAITING, RUNNING, PAUSED }

	public enum MissPolicy { SKIP_ALL, RUN_ONCE, RUN_ALL }


	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	private long id;

	@NotBlank(message = "name is mandatory")
	@Column(name="name")
	private String name;

	@Enumerated(EnumType.STRING)
	@Column(name="state")
	private State state;

	/**
	 * In Spring cron format.
	 * @see CronExpression#parse(String)
	 */
	@NotBlank(message = "cronExpression is mandatory")
	@Column(name="cron_expression")
	private String cronExpression;

	@NotBlank(message = "timeZone is mandatory")
	@Column(name="time_zone")
	private String timeZone;

	@Column(name="last_fired_time")
	private Long lastFiredTime;

	@Column(name="last_finished_time")
	private Long lastFinishedTime;

	@Column(name="next_fire_time")
	private Long nextFireTime;

	@NotBlank(message = "triggerable is mandatory")
	@Column(name="triggerable")
	private String triggerable;

	@NotNull(message = "priority is mandatory")
	@Column(name="priority")
	private int priority;

	@NotNull(message = "timeoutMs is mandatory")
	@Column(name="timeout_ms")
	private int timeoutMs;

	@NotNull(message = "missPolicy is mandatory")
	@Column(name="miss_policy")
	@Enumerated(EnumType.STRING)
	private MissPolicy missPolicy;

	@Column(name="last_initiator")
	private String lastInitiator;

	@OrderBy("id")
	@OneToMany(targetEntity = ScheduledTaskArg.class, mappedBy="scheduledTask", fetch=FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
	@Fetch(value = FetchMode.SUBSELECT)
	private List args;


	public long getId() {
		return id;
	}

	public String getName() {
		return name;
	}

	public State getState() {
		return state;
	}

	public void setState(State state) {
		this.state = state;
	}

	public String getCronExpression() {
		return cronExpression;
	}

	public Long getLastFiredTime() {
		return lastFiredTime;
	}

	public Long getLastFinishedTime() {
		return lastFinishedTime;
	}

	public Long getNextFireTime() {
		return nextFireTime;
	}

	@JsonIgnore
	public Instant getNextFireTimeInstant() {
		return nextFireTime != null ? Instant.ofEpochMilli(nextFireTime) : null;
	}

	public void setNextFireTime(Long nextFireTime) {
		this.nextFireTime = nextFireTime;
	}

	public String getTriggerable() {
		return triggerable;
	}

	public int getPriority() {
		return priority;
	}

	public int getTimeoutMs() {
		return timeoutMs;
	}

	public MissPolicy getMissPolicy() {
		return missPolicy;
	}

	public String getLastInitiator() {
		return lastInitiator;
	}

	public Map getArgs() {
		return args.stream().collect(Collectors.toMap(
				ScheduledTaskArg::getName,
				ScheduledTaskArg::getValue));
	}

	public void setArgs(Map args) {
		if (this.args == null)
			this.args = new ArrayList<>(args.size());
		else
			this.args.clear();

		args.forEach((k, v) -> {
			ScheduledTaskArg arg = new ScheduledTaskArg(k, v);
			this.args.add(arg);
			arg.setScheduledTask(this);
		});
	}

	@JsonIgnore
	public List getScheduledTaskArgs() {
		return args;
	}

	public String getTimeZone() {
		return timeZone;
	}

	public Optional calculateNextFireTime(Instant now) {
		Instant instant = now;
		if (missPolicy == MissPolicy.RUN_ALL && lastFiredTime != null)
			instant = Instant.ofEpochMilli(lastFiredTime);

		ZoneId zoneId = ZoneId.of(timeZone);
		ZonedDateTime base = instant.atZone(zoneId);
		return Optional.ofNullable(CronExpression.parse(cronExpression).next(base))
				.map(ZonedDateTime::toInstant);
	}

	public void setRunning(Instant now) {
		this.state = State.RUNNING;
		this.lastFiredTime = now.toEpochMilli();
	}


	public void updateLastFinishedTime() {
		this.lastFinishedTime = Instant.now().toEpochMilli();
	}


	@Override
	public String toString() {
		return "ScheduledTask [id=" + id + ", name=" + name + ", state=" + state + ", cronExpression=" +
				cronExpression + ", timeZone=" + timeZone + ", lastFiredTime=" + lastFiredTime + ", lastFinishedTime=" +
				lastFinishedTime + ", nextFireTime=" + nextFireTime + ", triggerable=" + triggerable + ", priority=" +
				priority + ", timeoutMs=" + timeoutMs + ", missPolicy=" + missPolicy + ", lastInitiator=" +
				lastInitiator + ", args=" + args + "]";
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy