package com.rupertjones.globalcron.common.domain;
import com.rupertjones.globalcron.common.audit.Auditable;
import com.rupertjones.globalcron.common.scheduling.Executable;
import com.rupertjones.globalcron.common.util.TimeZoneSource;
import org.hibernate.annotations.Cascade;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OrderBy;
import javax.persistence.Table;
import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import static java.lang.String.format;
@Entity
@Table(name = "job")
public class JobDescriptor extends BaseEntity implements Auditable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
@Column(name = "name")
private String name = null;
@Column(name = "timezone")
private String timezone;
@Column(name = "script")
private String script;
@Column(name = "cron")
private String cron;
@Column(name = "enabled")
private boolean enabled = false;
@Column(name = "last_modified")
private long lastModified;
@Column(name = "save_output")
private boolean saveOutput = false;
@Column(name = "wait_for_complete")
private boolean waitForCompletion = false;
@Column(name = "allow_adhoc_exec")
private boolean allowAdhocExec = false;
@Column(name = "last_fire")
private Date lastFireServer = null;
@Column(name = "next_fire")
private Date nextFireServer = null;
@ManyToOne
@JoinColumn(name = "host")
private Host host;
@Column(name = "version")
private int version;
@OneToMany(mappedBy = "job", orphanRemoval = true, cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.ALL })
@Access(value = AccessType.PROPERTY)
@Cascade({ org.hibernate.annotations.CascadeType.ALL })
@OrderBy(value = "lastModified desc")
private List<JobExecutionLog> logs = new ArrayList<JobExecutionLog>();
@Column(name = "deleted")
private boolean deleted;
@Column(name = "wait_after")
private long waitAfter = 0;
public DateTime getLastFire() {
if (lastFireServer != null) {
return new DateTime(lastFireServer, host.getTimeZone());
}
return null;
}
public DateTime getNextFire() {
if (nextFireServer != null) {
return new DateTime(nextFireServer, host.getTimeZone());
}
return null;
}
public DateTime getNextFireAtExecutionTimezone() {
if (getNextFire() != null) {
return getNextFire().withZone(getTimezoneAsObject());
}
return null;
}
public DateTime getLastFireAtExecutionTimezone() {
if (getLastFire() != null) {
return getLastFire().withZone(getTimezoneAsObject());
}
return null;
}
public List<JobExecutionLog> getLogs() {
return logs;
}
public void setLogs(List<JobExecutionLog> logs) {
this.logs = logs;
}
public long getWaitAfter() {
return waitAfter;
}
public void setWaitAfter(long waitAfter) {
this.waitAfter = waitAfter;
}
public boolean isSaveOutput() {
return saveOutput;
}
public void setSaveOutput(boolean saveOutput) {
this.saveOutput = saveOutput;
}
public boolean isWaitForCompletion() {
return waitForCompletion;
}
public void setWaitForCompletion(boolean waitForCompletion) {
this.waitForCompletion = waitForCompletion;
}
public long getLastModified() {
return lastModified;
}
public void setLastModified(long lastModified) {
this.lastModified = lastModified;
}
public Host getHost() {
return host;
}
public void setHost(Host host) {
this.host = host;
}
public int getVersion() {
return version;
}
public void setVersion(int version) {
this.version = version;
}
public String getName() {
return name;
}
public String getKey() {
return String.format("%s-%s", getId(), getName().toLowerCase().trim().replace(" ", "_"));
}
public void setName(String name) {
this.name = name;
}
public String getTimezone() {
return timezone;
}
public DateTimeZone getTimezoneAsObject() {
return TimeZoneSource.fromId(getTimezone());
}
public void setTimezone(String timezone) {
this.timezone = timezone;
}
public void setScript(String script) {
this.script = script;
}
public String getScript() {
return script;
}
public Executable getRunnable() {
Executable exec = new Executable(this);
return exec;
}
public String getCron() {
return cron;
}
public void setCron(String cron) {
this.cron = cron;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public boolean isEnabled() {
return enabled;
}
public boolean canStart() {
return enabled && !deleted;
}
@Override
public void setId(int id) {
this.id = id;
}
@Override
public int getId() {
return this.id;
}
public void addOutput(JobExecutionLog jobExecutionLog) {
this.logs.add(jobExecutionLog);
}
public void setDeleted(boolean deleted) {
this.deleted = deleted;
}
public boolean isDeleted() {
return deleted;
}
public boolean isAllowAdhocExec() {
return allowAdhocExec;
}
public void setAllowAdhocExec(boolean allowAdhocExec) {
this.allowAdhocExec = allowAdhocExec;
}
public void incrementVersion() {
version++;
}
public boolean canRun() {
return canStart() && runOnHost();
}
public boolean runOnHost() {
return host.isEnabled() && runOnThisHost();
}
public boolean runOnThisHost() {
return Host.getCurrentHost().equals(host.getHostname());
}
public boolean hasWaitAfter() {
return waitAfter > 0;
}
public void updateLastFire(Date lastFire) {
this.lastFireServer = lastFire;
}
public void updateNextFire(Date nextFire) {
this.nextFireServer = nextFire;
}
public String toReportingLine() {
StringBuilder buffer = new StringBuilder();
buffer.append(format("[id: %s] [name: %s] [enabled: %s] [host: %s] [cron: %s] [script: %s] [next fire (@server): %s] [next fire (@%s): %s]",
getId(), getName(), isEnabled(), getHost().getHostname(), getCron(), getScript(), getNextFire(), getTimezone(), getNextFireAtExecutionTimezone()));
return buffer.toString();
}
@Override
public String toAuditLog() {
return toReportingLine();
}
@Override
public AuditLogType getAuditTypeForUpdate() {
return AuditLogType.EDIT_JOB;
}
@Override
public AuditLogType getAuditTypeForInsert() {
return AuditLogType.ADD_JOB;
}
@Override
public String toString() {
return toReportingLine();
}
public boolean scriptExists() {
return new File(script).exists();
}
}