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