mirror of https://github.com/micromata/borgbackup-butler.git

Kai Reinhard
24.52.2019 c50335dff01dffab42f4f25639eb14c11d80a70c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package de.micromata.borgbutler.jobs;
 
import de.micromata.borgbutler.utils.DateUtils;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
import java.time.LocalDateTime;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
 
public abstract class AbstractJob<T> {
    private Logger logger = LoggerFactory.getLogger(AbstractJob.class);
 
    public enum Status {DONE, RUNNING, QUEUED, CANCELLED, FAILED}
 
    @Getter
    @Setter
    private boolean cancellationRequested;
    @Getter
    private Status status;
    @Getter
    @Setter
    private String title;
    @Getter(AccessLevel.PACKAGE)
    @Setter(AccessLevel.PACKAGE)
    private Future<JobResult<T>> future;
    @Getter
    @Setter(AccessLevel.PROTECTED)
    private long uniqueJobNumber = -1;
    @Getter
    @Setter
    private String createTime;
    @Getter
    @Setter
    private String startTime;
    @Getter
    @Setter
    private String stopTime;
 
    protected AbstractJob<T> setStatus(Status status) {
        if (status == Status.RUNNING && this.status != Status.RUNNING) {
            this.startTime = DateUtils.format(LocalDateTime.now());
        } else if (status != Status.RUNNING && this.status == Status.RUNNING) {
            this.stopTime = DateUtils.format(LocalDateTime.now());
        }
        this.status = status;
        return this;
    }
 
    public void cancel() {
        if (this.getStatus() == Status.QUEUED) {
            setStatus(Status.CANCELLED);
        }
        this.cancellationRequested = true;
        cancelRunningProcess();
    }
 
    protected void setCancelled() {
        setStatus(Status.CANCELLED);
    }
 
    /**
     * Not supported if not implemented.
     */
    protected void cancelRunningProcess() {
    }
 
    /**
     * Waits for and gets the result.
     *
     * @return
     */
    public JobResult<T> getResult() {
        try {
            return future.get();
        } catch (InterruptedException | ExecutionException ex) {
            logger.error(ex.getMessage(), ex);
        }
        return null;
    }
 
    public T getResultObject() {
        return getResult().getResultObject();
    }
 
    protected void failed() {
        if (this.status == Status.CANCELLED) {
            // do nothing. It's normal that cancelled jobs fail.
            return;
        }
        if (this.status != Status.RUNNING) {
            logger.error("Internal error, illegal state! You shouldn't set the job status to FAILED if not in status RUNNING: " + this.status);
        }
        setStatus(Status.FAILED);
    }
 
    /**
     * @return true, if the job is done, stopped or failed. Otherwise false (if job is running or queued).
     */
    public boolean isFinished() {
        if (status == Status.DONE || status == Status.CANCELLED || status == Status.FAILED) {
            return true;
        }
        return false;
    }
 
    public abstract JobResult<T> execute();
 
    /**
     * A job is identified by this id. If a job with the same id is already queued (not yet finished), this job will
     * not be added twice.
     *
     * @return
     */
    public abstract Object getId();
 
    protected AbstractJob() {
        this.createTime = DateUtils.format(LocalDateTime.now());
    }
}