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

fi.evolver.basics.spring.job.entity.TaskStatus Maven / Gradle / Ivy

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

import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.security.DigestOutputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.zip.GZIPOutputStream;

import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import fi.evolver.utils.ServerUtils;
import fi.evolver.utils.format.FormatUtils;
import fi.evolver.utils.stream.VoidOutputStream;
import jakarta.persistence.*;


@Entity
@Table(name="task_status")
public class TaskStatus {
	private static final Logger LOG = LoggerFactory.getLogger(TaskStatus.class);

	public enum TaskState {
		RUNNING(false, false),
		DONE(true, true),
		NOTHING_TO_DO(true, true),
		CANCELLED(true, true),
		CANCELLING(true, true),
		FAILED(true, false);

		private final boolean finished;
		private final boolean success;

		TaskState(boolean finished, boolean success) {
			this.finished = finished;
			this.success = success;
		}

		public boolean isFinished() {
			return finished;
		}

		public boolean isSuccess() {
			return success;
		}
	}


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

	@Column(name="app_server", nullable=false)
	private String appServer;

	@Column(name="app_version")
	private String appVersion;

	@Column(name="group_name", nullable=false)
	private String group;

	@Column(name="description", nullable=false)
	private String description;

	@Column(name="start_time", nullable=false)
	private LocalDateTime startTime;

	@Column(name="message")
	private String message;

	@Column(name="state", nullable=false)
	@Enumerated(EnumType.STRING)
	private TaskState state;

	@Column(name="duration")
	private Long durationMs;

	@Column(name="last_updated", nullable=false)
	private LocalDateTime lastUpdated;

	@OrderBy("key")
	@Fetch(value = FetchMode.SUBSELECT)
	@OneToMany(mappedBy="taskStatus", fetch=FetchType.EAGER)
	private List metadata;


	public TaskStatus() {}

	public TaskStatus(String group, String description, String message, String appVersion, Map metadata) {
	    LocalDateTime now = LocalDateTime.now();
		this.appServer = ServerUtils.LOCAL_HOST_NAME;
		this.appVersion = FormatUtils.truncatePretty(appVersion, 64);

		this.metadata = new ArrayList<>();
		metadata.forEach(this::addMetadata);

		this.group = group;
		this.description = FormatUtils.truncatePretty(description, 1024);
		this.startTime = now;
		this.state = TaskState.RUNNING;
		this.lastUpdated = now;

		setMessage(message);
	}


	public long getId() {
		return id;
	}

	public String getAppServer() {
		return appServer;
	}

	public String getAppVersion() {
		return appVersion;
	}

	public String getGroup() {
		return group;
	}

	public String getDescription() {
		return description;
	}

	public LocalDateTime getStartTime() {
		return startTime;
	}

	public Optional getMessage() {
		return Optional.ofNullable(message);
	}

	public void setMessage(String message) {
		this.message = FormatUtils.truncatePretty(message, 512);
	}

	public List getMetadata() {
		return metadata;
	}

	public void addMetadata(String key, Object value) {
		if (key != null && value != null) {
			String valueString = Objects.toString(value);
			if (valueString.length() > 1024)
				valueString = digest(valueString);

			TaskStatusMetadata metadatum = new TaskStatusMetadata(key, valueString);
			metadatum.setTaskStatus(this);
			this.metadata.add(metadatum);
		}
	}

	public void setMetadata(List metadata) {
		this.metadata = metadata;
	}


	public TaskState getState() {
		return state;
	}

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

	public Optional getDurationMs() {
		return Optional.ofNullable(durationMs);
	}

	public LocalDateTime getLastUpdated() {
		return lastUpdated;
	}

	public Optional getMetadata(String key) {
		return metadata.stream().filter(m -> key.equals(m.getKey())).findAny().map(TaskStatusMetadata::getValue);
	}


	@PreUpdate
	protected void onUpdate() {
		lastUpdated = LocalDateTime.now();
		durationMs = ChronoUnit.MILLIS.between(startTime, lastUpdated);
	}


	private static String digest(String data) {
		if (data == null)
			return null;

		try (OutputStream v = new VoidOutputStream()) {
			DigestOutputStream out = new DigestOutputStream(v, MessageDigest.getInstance("MD5"));
			try (Writer writer = new OutputStreamWriter(new GZIPOutputStream(out))) {
				writer.write(data);
			}

			return FormatUtils.toHex(out.getMessageDigest().digest());
		}
		catch (IOException | NoSuchAlgorithmException | RuntimeException e) {
			LOG.error("Failed generating digest", e);
			return null;
		}
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy