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