001/*
002 * Licensed under the Apache License, Version 2.0 (the "License");
003 * you may not use this file except in compliance with the License.
004 * You may obtain a copy of the License at
005 *
006 *     http://www.apache.org/licenses/LICENSE-2.0
007 *
008 * Unless required by applicable law or agreed to in writing, software
009 * distributed under the License is distributed on an "AS IS" BASIS,
010 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
011 * See the License for the specific language governing permissions and
012 * limitations under the License.
013 */
014package org.gbif.api.model.pipelines;
015
016import com.fasterxml.jackson.annotation.JsonInclude;
017import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
018import com.fasterxml.jackson.databind.annotation.JsonSerialize;
019import java.io.Serializable;
020import java.time.LocalDateTime;
021import java.util.Comparator;
022import java.util.HashSet;
023import java.util.Objects;
024import java.util.Set;
025import java.util.StringJoiner;
026import org.gbif.api.jackson.LocalDateTimeSerDe;
027import org.gbif.api.model.registry.LenientEquals;
028
029/** Models a step in pipelines. */
030public class PipelineStep implements LenientEquals<PipelineStep>, Serializable {
031
032  private static final long serialVersionUID = 460047082156621661L;
033
034  @JsonInclude(JsonInclude.Include.NON_DEFAULT)
035  private long key;
036
037  private StepType type;
038  private StepRunner runner;
039
040  @JsonSerialize(using = LocalDateTimeSerDe.LocalDateTimeSerializer.class)
041  @JsonDeserialize(using = LocalDateTimeSerDe.LocalDateTimeDeserializer.class)
042  private LocalDateTime started;
043
044  @JsonSerialize(using = LocalDateTimeSerDe.LocalDateTimeSerializer.class)
045  @JsonDeserialize(using = LocalDateTimeSerDe.LocalDateTimeDeserializer.class)
046  private LocalDateTime finished;
047
048  private Status state;
049  private String message;
050  private Long numberRecords;
051  private String pipelinesVersion;
052  private String createdBy;
053
054  @JsonSerialize(using = LocalDateTimeSerDe.LocalDateTimeSerializer.class)
055  @JsonDeserialize(using = LocalDateTimeSerDe.LocalDateTimeDeserializer.class)
056  private LocalDateTime modified;
057
058  private String modifiedBy;
059  private Set<MetricInfo> metrics = new HashSet<>();
060
061  public static final Comparator<PipelineStep> STEPS_BY_TYPE_ASC =
062      (s1, s2) -> {
063        StepType st1 = s1 != null ? s1.getType() : null;
064        StepType st2 = s2 != null ? s2.getType() : null;
065
066        if (st1 == null) {
067          return (st2 == null) ? 0 : 1;
068        } else if (st2 == null) {
069          return -1;
070        }
071        return st1.compareTo(st2);
072      };
073
074  /**
075   * Comparator that sorts pipeline steps by start date and then by finished date in ascending
076   * order.
077   */
078  public static final Comparator<PipelineStep> STEPS_BY_FINISHED_ASC =
079      (s1, s2) -> {
080        LocalDateTime finished1 = s1 != null ? s1.getFinished() : null;
081        LocalDateTime finished2 = s2 != null ? s2.getFinished() : null;
082
083        if (finished1 == null && finished2 == null) {
084          return STEPS_BY_TYPE_ASC.compare(s1, s2);
085        }
086
087        if (finished1 == null) {
088          return 1;
089        } else if (finished2 == null) {
090          return -1;
091        }
092
093        if (finished1.equals(finished2)) {
094          return STEPS_BY_TYPE_ASC.compare(s1, s2);
095        }
096
097        return finished1.compareTo(finished2);
098      };
099
100  public long getKey() {
101    return key;
102  }
103
104  public StepType getType() {
105    return type;
106  }
107
108  public PipelineStep setType(StepType type) {
109    this.type = type;
110    return this;
111  }
112
113  public StepRunner getRunner() {
114    return runner;
115  }
116
117  public PipelineStep setRunner(StepRunner runner) {
118    this.runner = runner;
119    return this;
120  }
121
122  public LocalDateTime getStarted() {
123    return started;
124  }
125
126  public PipelineStep setStarted(LocalDateTime started) {
127    this.started = started;
128    return this;
129  }
130
131  public LocalDateTime getFinished() {
132    return finished;
133  }
134
135  public PipelineStep setFinished(LocalDateTime finished) {
136    this.finished = finished;
137    return this;
138  }
139
140  public Status getState() {
141    return state;
142  }
143
144  public PipelineStep setState(Status state) {
145    this.state = state;
146    return this;
147  }
148
149  public String getMessage() {
150    return message;
151  }
152
153  public PipelineStep setMessage(String message) {
154    this.message = message;
155    return this;
156  }
157
158  public PipelineStep setKey(long key) {
159    this.key = key;
160    return this;
161  }
162
163  public Long getNumberRecords() {
164    return numberRecords;
165  }
166
167  public PipelineStep setNumberRecords(Long numberRecords) {
168    this.numberRecords = numberRecords;
169    return this;
170  }
171
172  public String getPipelinesVersion() {
173    return pipelinesVersion;
174  }
175
176  public PipelineStep setPipelinesVersion(String pipelinesVersion) {
177    this.pipelinesVersion = pipelinesVersion;
178    return this;
179  }
180
181  public String getCreatedBy() {
182    return createdBy;
183  }
184
185  public PipelineStep setCreatedBy(String createdBy) {
186    this.createdBy = createdBy;
187    return this;
188  }
189
190  public LocalDateTime getModified() {
191    return modified;
192  }
193
194  public PipelineStep setModified(LocalDateTime modified) {
195    this.modified = modified;
196    return this;
197  }
198
199  public String getModifiedBy() {
200    return modifiedBy;
201  }
202
203  public PipelineStep setModifiedBy(String modifiedBy) {
204    this.modifiedBy = modifiedBy;
205    return this;
206  }
207
208  public Set<MetricInfo> getMetrics() {
209    return metrics;
210  }
211
212  public PipelineStep setMetrics(Set<MetricInfo> metrics) {
213    this.metrics = metrics;
214    return this;
215  }
216
217  public PipelineStep addMetricInfo(MetricInfo metricInfo) {
218    metrics.add(metricInfo);
219    return this;
220  }
221
222  /** Enum to represent the status of a step. */
223  public enum Status {
224    RUNNING,
225    FAILED,
226    SUBMITTED,
227    COMPLETED,
228    ABORTED,
229    QUEUED
230  }
231
232  /** Inner class to store metrics. */
233  public static class MetricInfo implements Serializable {
234
235    private static final long serialVersionUID = 1872427841009786709L;
236
237    private String name;
238    private String value;
239
240    public MetricInfo() {
241      // needed for jackson
242    }
243
244    public MetricInfo(String name, String value) {
245      this.name = name;
246      this.value = value;
247    }
248
249    public String getName() {
250      return name;
251    }
252
253    public String getValue() {
254      return value;
255    }
256
257    public void setName(String name) {
258      this.name = name;
259    }
260
261    public void setValue(String value) {
262      this.value = value;
263    }
264
265    @Override
266    public boolean equals(Object o) {
267      if (this == o) {
268        return true;
269      }
270      if (o == null || getClass() != o.getClass()) {
271        return false;
272      }
273      MetricInfo that = (MetricInfo) o;
274      return Objects.equals(name, that.name) && Objects.equals(value, that.value);
275    }
276
277    @Override
278    public int hashCode() {
279      return Objects.hash(name, value);
280    }
281
282    @Override
283    public String toString() {
284      return new StringJoiner(", ", MetricInfo.class.getSimpleName() + "[", "]")
285          .add("name='" + name + "'")
286          .add("value='" + value + "'")
287          .toString();
288    }
289  }
290
291  @Override
292  public boolean equals(Object o) {
293    if (this == o) return true;
294    if (o == null || getClass() != o.getClass()) return false;
295    PipelineStep that = (PipelineStep) o;
296    return key == that.key
297        && Objects.equals(type, that.type)
298        && Objects.equals(runner, that.runner)
299        && Objects.equals(started, that.started)
300        && Objects.equals(finished, that.finished)
301        && state == that.state
302        && Objects.equals(message, that.message)
303        && Objects.equals(metrics, that.metrics)
304        && Objects.equals(numberRecords, that.numberRecords)
305        && Objects.equals(pipelinesVersion, that.pipelinesVersion)
306        && Objects.equals(createdBy, that.createdBy)
307        && Objects.equals(modified, that.modified)
308        && Objects.equals(modifiedBy, that.modifiedBy);
309  }
310
311  @Override
312  public int hashCode() {
313    return Objects.hash(
314        key,
315        type,
316        runner,
317        started,
318        finished,
319        state,
320        message,
321        metrics,
322        numberRecords,
323        pipelinesVersion,
324        createdBy,
325        modified,
326        modifiedBy);
327  }
328
329  @Override
330  public String toString() {
331    return new StringJoiner(", ", PipelineStep.class.getSimpleName() + "[", "]")
332        .add("key=" + key)
333        .add("type=" + type)
334        .add("runner=" + runner)
335        .add("started=" + started)
336        .add("finished=" + finished)
337        .add("state=" + state)
338        .add("message='" + message + "'")
339        .add("numberRecords='" + numberRecords + "'")
340        .add("pipelinesVersion='" + pipelinesVersion + "'")
341        .add("createdBy='" + createdBy + "'")
342        .add("modified=" + modified)
343        .add("modifiedBy='" + modifiedBy + "'")
344        .add("metrics=" + metrics)
345        .toString();
346  }
347
348  @Override
349  public boolean lenientEquals(PipelineStep other) {
350    if (this == other) return true;
351    return Objects.equals(type, other.type)
352        && Objects.equals(runner, other.runner)
353        && Objects.equals(finished, other.finished)
354        && state == other.state
355        && Objects.equals(message, other.message)
356        && Objects.equals(metrics, other.metrics)
357        && Objects.equals(numberRecords, other.numberRecords)
358        && Objects.equals(pipelinesVersion, other.pipelinesVersion);
359  }
360}