001/**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *      http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019package org.apache.oozie;
020
021import java.io.DataInput;
022import java.io.DataOutput;
023import java.io.IOException;
024import java.sql.Timestamp;
025import java.text.MessageFormat;
026import java.util.Date;
027import java.util.List;
028import java.util.Properties;
029
030import javax.persistence.Basic;
031import javax.persistence.Column;
032import javax.persistence.Entity;
033import javax.persistence.Id;
034import javax.persistence.Lob;
035import javax.persistence.NamedQueries;
036import javax.persistence.NamedQuery;
037import javax.persistence.Table;
038
039import org.apache.hadoop.io.Writable;
040import org.apache.oozie.client.WorkflowAction;
041import org.apache.oozie.client.rest.JsonBean;
042import org.apache.oozie.client.rest.JsonTags;
043import org.apache.oozie.client.rest.JsonUtils;
044import org.apache.oozie.util.DateUtils;
045import org.apache.oozie.util.ParamChecker;
046import org.apache.oozie.util.PropertiesUtils;
047import org.apache.oozie.util.WritableUtils;
048import org.apache.openjpa.persistence.jdbc.Index;
049import org.apache.openjpa.persistence.jdbc.Strategy;
050
051import org.json.simple.JSONArray;
052import org.json.simple.JSONObject;
053
054/**
055 * Bean that contains all the information to start an action for a workflow
056 * node.
057 */
058@Entity
059@NamedQueries({
060
061    @NamedQuery(name = "UPDATE_ACTION", query = "update WorkflowActionBean a set a.conf = :conf, a.consoleUrl = :consoleUrl, a.data = :data, a.stats = :stats, a.externalChildIDs = :externalChildIDs, a.errorCode = :errorCode, a.errorMessage = :errorMessage, a.externalId = :externalId, a.externalStatus = :externalStatus, a.name = :name, a.cred = :cred , a.retries = :retries, a.trackerUri = :trackerUri, a.transition = :transition, a.type = :type, a.endTimestamp = :endTime, a.executionPath = :executionPath, a.lastCheckTimestamp = :lastCheckTime, a.logToken = :logToken, a.pending = :pending, a.pendingAgeTimestamp = :pendingAge, a.signalValue = :signalValue, a.slaXml = :slaXml, a.startTimestamp = :startTime, a.statusStr = :status, a.wfId=:wfId where a.id = :id"),
062
063    @NamedQuery(name = "UPDATE_ACTION_FOR_LAST_CHECKED_TIME", query = "update WorkflowActionBean a set a.lastCheckTimestamp = :lastCheckTime where a.id = :id"),
064
065    @NamedQuery(name = "UPDATE_ACTION_START", query = "update WorkflowActionBean a set a.startTimestamp = :startTime, a.externalChildIDs = :externalChildIDs, a.conf = :conf, a.errorCode = :errorCode, a.errorMessage = :errorMessage, a.startTimestamp = :startTime, a.externalId = :externalId, a.trackerUri = :trackerUri, a.consoleUrl = :consoleUrl, a.lastCheckTimestamp = :lastCheckTime, a.statusStr = :status, a.externalStatus = :externalStatus, a.data = :data, a.retries = :retries, a.pending = :pending, a.pendingAgeTimestamp = :pendingAge, a.userRetryCount = :userRetryCount where a.id = :id"),
066
067    @NamedQuery(name = "UPDATE_ACTION_CHECK", query = "update WorkflowActionBean a set a.userRetryCount = :userRetryCount, a.stats = :stats, a.externalChildIDs = :externalChildIDs, a.externalStatus = :externalStatus, a.statusStr = :status, a.data = :data, a.pending = :pending, a.errorCode = :errorCode, a.errorMessage = :errorMessage, a.lastCheckTimestamp = :lastCheckTime, a.retries = :retries, a.pendingAgeTimestamp = :pendingAge, a.startTimestamp = :startTime where a.id = :id"),
068
069    @NamedQuery(name = "UPDATE_ACTION_END", query = "update WorkflowActionBean a set a.stats = :stats, a.errorCode = :errorCode, a.errorMessage = :errorMessage, a.retries = :retries, a.endTimestamp = :endTime, a.statusStr = :status, a.pending = :pending, a.pendingAgeTimestamp = :pendingAge, a.signalValue = :signalValue, a.userRetryCount = :userRetryCount, a.externalStatus = :externalStatus where a.id = :id"),
070
071    @NamedQuery(name = "UPDATE_ACTION_PENDING", query = "update WorkflowActionBean a set a.pending = :pending, a.pendingAgeTimestamp = :pendingAge, a.executionPath = :executionPath where a.id = :id"),
072
073    @NamedQuery(name = "UPDATE_ACTION_STATUS_PENDING", query = "update WorkflowActionBean a set a.statusStr = :status, a.pending = :pending, a.pendingAgeTimestamp = :pendingAge where a.id = :id"),
074
075    @NamedQuery(name = "UPDATE_ACTION_PENDING_TRANS", query = "update WorkflowActionBean a set a.pending = :pending, a.pendingAgeTimestamp = :pendingAge, a.transition = :transition where a.id = :id"),
076
077    @NamedQuery(name = "UPDATE_ACTION_PENDING_TRANS_ERROR", query = "update WorkflowActionBean a set a.pending = :pending, a.pendingAgeTimestamp = :pendingAge, a.transition = :transition, a.errorCode = :errorCode, a.errorMessage = :errorMessage, a.statusStr = :status where a.id = :id"),
078
079    @NamedQuery(name = "DELETE_ACTION", query = "delete from WorkflowActionBean a where a.id IN (:id)"),
080
081    @NamedQuery(name = "DELETE_ACTIONS_FOR_WORKFLOW", query = "delete from WorkflowActionBean a where a.wfId IN (:wfId)"),
082
083    @NamedQuery(name = "GET_ACTIONS", query = "select OBJECT(a) from WorkflowActionBean a"),
084
085    @NamedQuery(name = "GET_ACTION", query = "select OBJECT(a) from WorkflowActionBean a where a.id = :id"),
086
087    @NamedQuery(name = "GET_ACTION_ID_TYPE_LASTCHECK", query = "select a.id, a.type, a.lastCheckTimestamp from WorkflowActionBean a where a.id = :id"),
088
089    @NamedQuery(name = "GET_ACTION_FAIL", query = "select a.id, a.wfId, a.name, a.statusStr, a.pending, a.type, a.logToken, a.transition, a.errorCode, a.errorMessage from WorkflowActionBean a where a.id = :id"),
090
091    @NamedQuery(name = "GET_ACTION_SIGNAL", query = "select a.id, a.wfId, a.name, a.statusStr, a.pending, a.pendingAgeTimestamp, a.type, a.logToken, a.transition, a.errorCode, a.errorMessage, a.executionPath, a.signalValue, a.slaXml, a.externalId from WorkflowActionBean a where a.id = :id"),
092
093    @NamedQuery(name = "GET_ACTION_CHECK", query = "select a.id, a.wfId, a.name, a.statusStr, a.pending, a.pendingAgeTimestamp, a.type, a.logToken, a.transition, a.retries, a.userRetryCount, a.userRetryMax, a.userRetryInterval, a.trackerUri, a.startTimestamp, a.endTimestamp, a.lastCheckTimestamp, a.errorCode, a.errorMessage, a.externalId, a.externalStatus, a.externalChildIDs, a.conf from WorkflowActionBean a where a.id = :id"),
094
095    @NamedQuery(name = "GET_ACTION_END", query = "select a.id, a.wfId, a.name, a.statusStr, a.pending, a.pendingAgeTimestamp, a.type, a.logToken, a.transition, a.retries, a.trackerUri, a.userRetryCount, a.userRetryMax, a.userRetryInterval, a.startTimestamp, a.endTimestamp, a.errorCode, a.errorMessage, a.externalId, a.externalStatus, a.externalChildIDs, a.conf, a.data, a.stats from WorkflowActionBean a where a.id = :id"),
096
097    @NamedQuery(name = "GET_ACTION_COMPLETED", query = "select a.id, a.wfId, a.statusStr, a.type, a.logToken from WorkflowActionBean a where a.id = :id"),
098
099    @NamedQuery(name = "GET_ACTION_FOR_UPDATE", query = "select OBJECT(a) from WorkflowActionBean a where a.id = :id"),
100
101    @NamedQuery(name = "GET_ACTION_FOR_SLA", query = "select a.id, a.statusStr, a.startTimestamp, a.endTimestamp from WorkflowActionBean a where a.id = :id"),
102
103    @NamedQuery(name = "GET_ACTIONS_FOR_WORKFLOW", query = "select OBJECT(a) from WorkflowActionBean a where a.wfId = :wfId order by a.startTimestamp"),
104
105    @NamedQuery(name = "GET_ACTIONS_OF_WORKFLOW_FOR_UPDATE", query = "select OBJECT(a) from WorkflowActionBean a where a.wfId = :wfId order by a.startTimestamp"),
106
107    @NamedQuery(name = "GET_PENDING_ACTIONS", query = "select a.id, a.wfId, a.statusStr, a.type, a.pendingAgeTimestamp from WorkflowActionBean a where a.pending = 1 AND a.pendingAgeTimestamp < :pendingAge AND a.statusStr <> 'RUNNING' AND a.createdTimeTS >= :createdTime"),
108
109    @NamedQuery(name = "GET_RUNNING_ACTIONS", query = "select a.id from WorkflowActionBean a where a.pending = 1 AND a.statusStr = 'RUNNING' AND a.lastCheckTimestamp < :lastCheckTime"),
110
111    @NamedQuery(name = "GET_RETRY_MANUAL_ACTIONS", query = "select OBJECT(a) from WorkflowActionBean a where a.wfId = :wfId AND (a.statusStr = 'START_RETRY' OR a.statusStr = 'START_MANUAL' OR a.statusStr = 'END_RETRY' OR a.statusStr = 'END_MANUAL')"),
112
113    @NamedQuery(name = "GET_ACTIONS_FOR_WORKFLOW_RERUN", query = "select a.id, a.name, a.statusStr, a.endTimestamp, a.type from WorkflowActionBean a where a.wfId = :wfId order by a.startTimestamp") })
114@Table(name = "WF_ACTIONS")
115public class WorkflowActionBean implements Writable, WorkflowAction, JsonBean {
116    @Id
117    private String id;
118
119    @Basic
120    @Index
121    @Column(name = "wf_id")
122    private String wfId = null;
123
124    @Basic
125    @Column(name = "created_time")
126    private Timestamp createdTimeTS = null;
127
128    @Basic
129    @Index
130    @Column(name = "status")
131    private String statusStr = WorkflowAction.Status.PREP.toString();
132
133    @Basic
134    @Column(name = "last_check_time")
135    private Timestamp lastCheckTimestamp;
136
137    @Basic
138    @Column(name = "end_time")
139    private Timestamp endTimestamp = null;
140
141    @Basic
142    @Column(name = "start_time")
143    private Timestamp startTimestamp = null;
144
145    @Basic
146    @Column(name = "execution_path", length = 1024)
147    private String executionPath = null;
148
149    @Basic
150    @Column(name = "pending")
151    private int pending = 0;
152
153    @Basic
154    @Index
155    @Column(name = "pending_age")
156    private Timestamp pendingAgeTimestamp = null;
157
158    @Basic
159    @Column(name = "signal_value")
160    private String signalValue = null;
161
162    @Basic
163    @Column(name = "log_token")
164    private String logToken = null;
165
166    @Basic
167    @Column(name = "sla_xml")
168    @Lob
169    @Strategy("org.apache.oozie.executor.jpa.StringBlobValueHandler")
170    private StringBlob slaXml;
171
172    @Basic
173    @Column(name = "name")
174    private String name = null;
175
176    @Basic
177    @Column(name = "cred")
178    private String cred = null;
179
180    @Basic
181    @Column(name = "type")
182    private String type = null;
183
184    @Basic
185    @Column(name = "conf")
186    @Lob
187    @Strategy("org.apache.oozie.executor.jpa.StringBlobValueHandler")
188    private StringBlob conf;
189
190    @Basic
191    @Column(name = "retries")
192    private int retries;
193
194    @Basic
195    @Column(name = "user_retry_count")
196    private int userRetryCount;
197
198    @Basic
199    @Column(name = "user_retry_max")
200    private int userRetryMax;
201
202    @Basic
203    @Column(name = "user_retry_interval")
204    private int userRetryInterval;
205
206    @Basic
207    @Column(name = "transition")
208    private String transition = null;
209
210    @Basic
211    @Column(name = "data")
212    @Lob
213    @Strategy("org.apache.oozie.executor.jpa.StringBlobValueHandler")
214    private StringBlob data;
215
216    @Basic
217    @Column(name = "stats")
218    @Lob
219    @Strategy("org.apache.oozie.executor.jpa.StringBlobValueHandler")
220    private StringBlob stats;
221
222    @Basic
223    @Column(name = "external_child_ids")
224    @Lob
225    @Strategy("org.apache.oozie.executor.jpa.StringBlobValueHandler")
226    private StringBlob externalChildIDs;
227
228    @Basic
229    @Column(name = "external_id")
230    private String externalId = null;
231
232    @Basic
233    @Column(name = "external_status")
234    private String externalStatus = null;
235
236    @Basic
237    @Column(name = "tracker_uri")
238    private String trackerUri = null;
239
240    @Basic
241    @Column(name = "console_url")
242    private String consoleUrl = null;
243
244    @Basic
245    @Column(name = "error_code")
246    private String errorCode = null;
247
248    @Column(name = "error_message", length = 500)
249    private String errorMessage = null;
250
251    /**
252     * Default constructor.
253     */
254    public WorkflowActionBean() {
255    }
256
257    /**
258     * Serialize the action bean to a data output.
259     *
260     * @param dataOutput data output.
261     * @throws IOException thrown if the action bean could not be serialized.
262     */
263
264    public void write(DataOutput dataOutput) throws IOException {
265        WritableUtils.writeStr(dataOutput, getId());
266        WritableUtils.writeStr(dataOutput, getName());
267        WritableUtils.writeStr(dataOutput, getCred());
268        WritableUtils.writeStr(dataOutput, getType());
269        WritableUtils.writeStr(dataOutput, getConf());
270        WritableUtils.writeStr(dataOutput, getStatusStr());
271        dataOutput.writeInt(getRetries());
272        dataOutput.writeLong((getStartTime() != null) ? getStartTime().getTime() : -1);
273        dataOutput.writeLong((getEndTime() != null) ? getEndTime().getTime() : -1);
274        dataOutput.writeLong((getLastCheckTime() != null) ? getLastCheckTime().getTime() : -1);
275        WritableUtils.writeStr(dataOutput, getTransition());
276        WritableUtils.writeStr(dataOutput, getData());
277        WritableUtils.writeStr(dataOutput, getStats());
278        WritableUtils.writeStr(dataOutput, getExternalChildIDs());
279        WritableUtils.writeStr(dataOutput, getExternalId());
280        WritableUtils.writeStr(dataOutput, getExternalStatus());
281        WritableUtils.writeStr(dataOutput, getTrackerUri());
282        WritableUtils.writeStr(dataOutput, getConsoleUrl());
283        WritableUtils.writeStr(dataOutput, getErrorCode());
284        WritableUtils.writeStr(dataOutput, getErrorMessage());
285        WritableUtils.writeStr(dataOutput, wfId);
286        WritableUtils.writeStr(dataOutput, executionPath);
287        dataOutput.writeInt(pending);
288        dataOutput.writeLong((getPendingAge() != null) ? getPendingAge().getTime() : -1);
289        WritableUtils.writeStr(dataOutput, signalValue);
290        WritableUtils.writeStr(dataOutput, logToken);
291        dataOutput.writeInt(getUserRetryCount());
292        dataOutput.writeInt(getUserRetryInterval());
293        dataOutput.writeInt(getUserRetryMax());
294    }
295
296    /**
297     * Deserialize an action bean from a data input.
298     *
299     * @param dataInput data input.
300     * @throws IOException thrown if the action bean could not be deserialized.
301     */
302    public void readFields(DataInput dataInput) throws IOException {
303        setId(WritableUtils.readStr(dataInput));
304        setName(WritableUtils.readStr(dataInput));
305        setCred(WritableUtils.readStr(dataInput));
306        setType(WritableUtils.readStr(dataInput));
307        setConf(WritableUtils.readStr(dataInput));
308        setStatus(WorkflowAction.Status.valueOf(WritableUtils.readStr(dataInput)));
309        setRetries(dataInput.readInt());
310        long d = dataInput.readLong();
311        if (d != -1) {
312            setStartTime(new Date(d));
313        }
314        d = dataInput.readLong();
315        if (d != -1) {
316            setEndTime(new Date(d));
317        }
318        d = dataInput.readLong();
319        if (d != -1) {
320            setLastCheckTime(new Date(d));
321        }
322        setTransition(WritableUtils.readStr(dataInput));
323        setData(WritableUtils.readStr(dataInput));
324        setStats(WritableUtils.readStr(dataInput));
325        setExternalChildIDs(WritableUtils.readStr(dataInput));
326        setExternalId(WritableUtils.readStr(dataInput));
327        setExternalStatus(WritableUtils.readStr(dataInput));
328        setTrackerUri(WritableUtils.readStr(dataInput));
329        setConsoleUrl(WritableUtils.readStr(dataInput));
330        setErrorInfo(WritableUtils.readStr(dataInput), WritableUtils.readStr(dataInput));
331        wfId = WritableUtils.readStr(dataInput);
332        executionPath = WritableUtils.readStr(dataInput);
333        pending = dataInput.readInt();
334        d = dataInput.readLong();
335        if (d != -1) {
336            pendingAgeTimestamp = DateUtils.convertDateToTimestamp(new Date(d));
337        }
338        signalValue = WritableUtils.readStr(dataInput);
339        logToken = WritableUtils.readStr(dataInput);
340        setUserRetryCount(dataInput.readInt());
341        setUserRetryInterval(dataInput.readInt());
342        setUserRetryMax(dataInput.readInt());
343    }
344
345    /**
346     * Return whether workflow action in terminal state or not
347     *
348     * @return
349     */
350    public boolean inTerminalState() {
351        boolean isTerminalState = false;
352        switch (WorkflowAction.Status.valueOf(statusStr)) {
353            case ERROR:
354            case FAILED:
355            case KILLED:
356            case OK:
357                isTerminalState = true;
358                break;
359            default:
360                break;
361        }
362        return isTerminalState;
363    }
364
365    /**
366     * Return if the action execution is complete.
367     *
368     * @return if the action start is complete.
369     */
370    public boolean isExecutionComplete() {
371        return getStatus() == WorkflowAction.Status.DONE;
372    }
373
374    /**
375     * Return if the action is START_RETRY or START_MANUAL or END_RETRY or
376     * END_MANUAL.
377     *
378     * @return boolean true if status is START_RETRY or START_MANUAL or
379     *         END_RETRY or END_MANUAL
380     */
381    public boolean isRetryOrManual() {
382        return (getStatus() == WorkflowAction.Status.START_RETRY || getStatus() == WorkflowAction.Status.START_MANUAL
383                || getStatus() == WorkflowAction.Status.END_RETRY || getStatus() == WorkflowAction.Status.END_MANUAL);
384    }
385
386    /**
387     * Return true if the action is USER_RETRY
388     *
389     * @return boolean true if status is USER_RETRY
390     */
391    public boolean isUserRetry() {
392        return (getStatus() == WorkflowAction.Status.USER_RETRY);
393    }
394
395    /**
396     * Return if the action is complete.
397     *
398     * @return if the action is complete.
399     */
400    public boolean isComplete() {
401        return getStatus() == WorkflowAction.Status.OK || getStatus() == WorkflowAction.Status.KILLED
402                || getStatus() == WorkflowAction.Status.ERROR;
403    }
404
405    /**
406     * Return if the action is complete with failure.
407     *
408     * @return if the action is complete with failure.
409     */
410    public boolean isTerminalWithFailure() {
411        boolean result = false;
412        switch (getStatus()) {
413            case FAILED:
414            case KILLED:
415            case ERROR:
416                result = true;
417        }
418        return result;
419    }
420
421    /**
422     * Set the action pending flag to true.
423     */
424    public void setPendingOnly() {
425        pending = 1;
426    }
427
428    /**
429     * Set the action as pending and the current time as pending.
430     */
431    public void setPending() {
432        pending = 1;
433        pendingAgeTimestamp = DateUtils.convertDateToTimestamp(new Date());
434    }
435
436    /**
437     * Set pending flag
438     */
439    public void setPending(int i) {
440        pending = i;
441    }
442
443    /**
444     * Set a time when the action will be pending, normally a time in the
445     * future.
446     *
447     * @param pendingAge the time when the action will be pending.
448     */
449    public void setPendingAge(Date pendingAge) {
450        this.pendingAgeTimestamp = DateUtils.convertDateToTimestamp(pendingAge);
451    }
452
453    /**
454     * Return the pending age of the action.
455     *
456     * @return the pending age of the action, <code>null</code> if the action is
457     *         not pending.
458     */
459    public Date getPendingAge() {
460        return DateUtils.toDate(pendingAgeTimestamp);
461    }
462
463    /**
464     * Return if the action is pending.
465     *
466     * @return if the action is pending.
467     */
468    public boolean isPending() {
469        return pending == 1 ? true : false;
470    }
471
472    /**
473     * Removes the pending flag and pendingAge from the action.
474     */
475    public void resetPending() {
476        pending = 0;
477        pendingAgeTimestamp = null;
478    }
479
480    /**
481     * Removes the pending flag from the action.
482     */
483    public void resetPendingOnly() {
484        pending = 0;
485    }
486
487    /**
488     * Increments the number of retries for the action.
489     */
490    public void incRetries() {
491        setRetries(getRetries() + 1);
492    }
493
494    /**
495     * Set a tracking information for an action, and set the action status to
496     * {@link org.apache.oozie.client.WorkflowAction.Status#DONE}
497     *
498     * @param externalId external ID for the action.
499     * @param trackerUri tracker URI for the action.
500     * @param consoleUrl console URL for the action.
501     */
502    public void setStartData(String externalId, String trackerUri, String consoleUrl) {
503        setExternalId(ParamChecker.notEmpty(externalId, "externalId"));
504        setTrackerUri(ParamChecker.notEmpty(trackerUri, "trackerUri"));
505        setConsoleUrl(ParamChecker.notEmpty(consoleUrl, "consoleUrl"));
506        Date now = new Date();
507        if (this.startTimestamp == null) {
508            setStartTime(now);
509        }
510        setLastCheckTime(now);
511        setStatus(Status.RUNNING);
512    }
513
514    /**
515     * Set the completion information for an action start. Sets the Action
516     * status to {@link org.apache.oozie.client.WorkflowAction.Status#DONE}
517     *
518     * @param externalStatus action external end status.
519     * @param actionData action output data, <code>null</code> if there is no
520     *        action output data.
521     */
522    public void setExecutionData(String externalStatus, Properties actionData) {
523        setStatus(Status.DONE);
524        setExternalStatus(ParamChecker.notEmpty(externalStatus, "externalStatus"));
525        if (actionData != null) {
526            setData(PropertiesUtils.propertiesToString(actionData));
527        }
528    }
529
530    /**
531     * Return the action statistics info.
532     *
533     * @return Json representation of the stats.
534     */
535    public String getExecutionStats() {
536        return getStats();
537    }
538
539    /**
540     * Set the action statistics info for the workflow action.
541     *
542     * @param jsonStats representation of the stats.
543     */
544    public void setExecutionStats(String jsonStats) {
545        setStats(jsonStats);
546    }
547
548    /**
549     * Return the external child IDs.
550     *
551     * @return externalChildIDs as a string.
552     */
553    @Override
554    public String getExternalChildIDs() {
555        return externalChildIDs == null ? null : externalChildIDs.getString();
556    }
557
558    /**
559     * Set the external child IDs for the workflow action.
560     *
561     * @param externalChildIDs as a string.
562     */
563    public void setExternalChildIDs(String externalChildIDs) {
564        if (this.externalChildIDs == null) {
565            this.externalChildIDs = new StringBlob(externalChildIDs);
566        }
567        else {
568            this.externalChildIDs.setString(externalChildIDs);
569        }
570    }
571
572    /**
573     * Set external child ids
574     *
575     * @param externalChildIDs
576     */
577    public void setExternalChildIDsBlob(StringBlob externalChildIDs) {
578        this.externalChildIDs = externalChildIDs;
579    }
580
581    /**
582     * Get external ChildIds
583     *
584     * @return
585     */
586    public StringBlob getExternalChildIDsBlob() {
587        return externalChildIDs;
588    }
589
590    /**
591     * Set the completion information for an action end.
592     *
593     * @param status action status, {@link org.apache.oozie.client.WorkflowAction.Status#OK} or
594     *        {@link org.apache.oozie.client.WorkflowAction.Status#ERROR} or
595     *        {@link org.apache.oozie.client.WorkflowAction.Status#KILLED}
596     * @param signalValue the signal value. In most cases, the value should be
597     *        OK or ERROR.
598     */
599    public void setEndData(Status status, String signalValue) {
600        if (status == null || (status != Status.OK && status != Status.ERROR && status != Status.KILLED)) {
601            throw new IllegalArgumentException("Action status must be OK, ERROR or KILLED. Received ["
602                    + status.toString() + "]");
603        }
604        if (status == Status.OK) {
605            setErrorInfo(null, null);
606        }
607        setStatus(status);
608        setSignalValue(ParamChecker.notEmpty(signalValue, "signalValue"));
609    }
610
611    /**
612     * Return the job Id.
613     *
614     * @return the job Id.
615     */
616    public String getJobId() {
617        return wfId;
618    }
619
620    /**
621     * Return the job Id.
622     *
623     * @return the job Id.
624     */
625    public String getWfId() {
626        return wfId;
627    }
628
629    /**
630     * Set the job id.
631     *
632     * @param id jobId;
633     */
634    public void setJobId(String id) {
635        this.wfId = id;
636    }
637
638    public void setSlaXml(String slaXmlStr) {
639        if (this.slaXml == null) {
640            this.slaXml = new StringBlob(slaXmlStr);
641        }
642        else {
643            this.slaXml.setString(slaXmlStr);
644        }
645    }
646
647    public String getSlaXml() {
648        return slaXml == null ? null : slaXml.getString();
649    }
650
651    public void setSlaXmlBlob(StringBlob slaXml) {
652        this.slaXml = slaXml;
653    }
654
655    public StringBlob getSlaXmlBlob() {
656        return slaXml;
657    }
658
659    /**
660     * Set status of job
661     *
662     * @param val
663     */
664    public void setStatus(Status val) {
665        this.statusStr = val.toString();
666    }
667
668    @Override
669    public Status getStatus() {
670        return Status.valueOf(this.statusStr);
671    }
672
673    /**
674     * Set status
675     *
676     * @param statusStr
677     */
678    public void setStatusStr(String statusStr) {
679        this.statusStr = statusStr;
680    }
681
682    /**
683     * Get status
684     *
685     * @return
686     */
687    public String getStatusStr() {
688        return statusStr;
689    }
690
691    /**
692     * Return the node execution path.
693     *
694     * @return the node execution path.
695     */
696    public String getExecutionPath() {
697        return executionPath;
698    }
699
700    /**
701     * Set the node execution path.
702     *
703     * @param executionPath the node execution path.
704     */
705    public void setExecutionPath(String executionPath) {
706        this.executionPath = executionPath;
707    }
708
709    /**
710     * Return the signal value for the action.
711     * <p>
712     * For decision nodes it is the choosen transition, for actions it is OK or
713     * ERROR.
714     *
715     * @return the action signal value.
716     */
717    public String getSignalValue() {
718        return signalValue;
719    }
720
721    /**
722     * Set the signal value for the action.
723     * <p>
724     * For decision nodes it is the choosen transition, for actions it is OK or
725     * ERROR.
726     *
727     * @param signalValue the action signal value.
728     */
729    public void setSignalValue(String signalValue) {
730        this.signalValue = signalValue;
731    }
732
733    /**
734     * Return the job log token.
735     *
736     * @return the job log token.
737     */
738    public String getLogToken() {
739        return logToken;
740    }
741
742    /**
743     * Set the job log token.
744     *
745     * @param logToken the job log token.
746     */
747    public void setLogToken(String logToken) {
748        this.logToken = logToken;
749    }
750
751    /**
752     * Return the action last check time
753     *
754     * @return the last check time
755     */
756    public Date getLastCheckTime() {
757        return DateUtils.toDate(lastCheckTimestamp);
758    }
759
760    /**
761     * Return the action last check time
762     *
763     * @return the last check time
764     */
765    public Timestamp getLastCheckTimestamp() {
766        return lastCheckTimestamp;
767    }
768
769    /**
770     * Return the action last check time
771     *
772     * @return the last check time
773     */
774    public Timestamp getStartTimestamp() {
775        return startTimestamp;
776    }
777
778    /**
779     * Return the action last check time
780     *
781     * @return the last check time
782     */
783    public Timestamp getEndTimestamp() {
784        return endTimestamp;
785    }
786
787    /**
788     * Return the action last check time
789     *
790     * @return the last check time
791     */
792    public Timestamp getPendingAgeTimestamp() {
793        return pendingAgeTimestamp;
794    }
795
796    /**
797     * Sets the action last check time
798     *
799     * @param lastCheckTime the last check time to set.
800     */
801    public void setLastCheckTime(Date lastCheckTime) {
802        this.lastCheckTimestamp = DateUtils.convertDateToTimestamp(lastCheckTime);
803    }
804
805    public int getPending() {
806        return this.pending;
807    }
808
809    @Override
810    public Date getStartTime() {
811        return DateUtils.toDate(startTimestamp);
812    }
813
814    /**
815     * Set start time
816     *
817     * @param startTime
818     */
819    public void setStartTime(Date startTime) {
820        this.startTimestamp = DateUtils.convertDateToTimestamp(startTime);
821    }
822
823    @Override
824    public Date getEndTime() {
825        return DateUtils.toDate(endTimestamp);
826    }
827
828    /**
829     * Set end time
830     *
831     * @param endTime
832     */
833    public void setEndTime(Date endTime) {
834        this.endTimestamp = DateUtils.convertDateToTimestamp(endTime);
835    }
836
837    @SuppressWarnings("unchecked")
838    public JSONObject toJSONObject() {
839        return toJSONObject("GMT");
840    }
841
842    @SuppressWarnings("unchecked")
843    public JSONObject toJSONObject(String timeZoneId) {
844        JSONObject json = new JSONObject();
845        json.put(JsonTags.WORKFLOW_ACTION_ID, id);
846        json.put(JsonTags.WORKFLOW_ACTION_NAME, name);
847        json.put(JsonTags.WORKFLOW_ACTION_AUTH, cred);
848        json.put(JsonTags.WORKFLOW_ACTION_TYPE, type);
849        json.put(JsonTags.WORKFLOW_ACTION_CONF, getConf());
850        json.put(JsonTags.WORKFLOW_ACTION_STATUS, statusStr);
851        json.put(JsonTags.WORKFLOW_ACTION_RETRIES, (long) retries);
852        json.put(JsonTags.WORKFLOW_ACTION_START_TIME, JsonUtils.formatDateRfc822(getStartTime(), timeZoneId));
853        json.put(JsonTags.WORKFLOW_ACTION_END_TIME, JsonUtils.formatDateRfc822(getEndTime(), timeZoneId));
854        json.put(JsonTags.WORKFLOW_ACTION_TRANSITION, transition);
855        json.put(JsonTags.WORKFLOW_ACTION_DATA, getData());
856        json.put(JsonTags.WORKFLOW_ACTION_STATS, getStats());
857        json.put(JsonTags.WORKFLOW_ACTION_EXTERNAL_CHILD_IDS, getExternalChildIDs());
858        json.put(JsonTags.WORKFLOW_ACTION_EXTERNAL_ID, externalId);
859        json.put(JsonTags.WORKFLOW_ACTION_EXTERNAL_STATUS, externalStatus);
860        json.put(JsonTags.WORKFLOW_ACTION_TRACKER_URI, trackerUri);
861        json.put(JsonTags.WORKFLOW_ACTION_CONSOLE_URL, consoleUrl);
862        json.put(JsonTags.WORKFLOW_ACTION_ERROR_CODE, errorCode);
863        json.put(JsonTags.WORKFLOW_ACTION_ERROR_MESSAGE, errorMessage);
864        json.put(JsonTags.TO_STRING, toString());
865        json.put(JsonTags.WORKFLOW_ACTION_USER_RETRY_INTERVAL, userRetryInterval);
866        json.put(JsonTags.WORKFLOW_ACTION_USER_RETRY_COUNT, userRetryCount);
867        json.put(JsonTags.WORKFLOW_ACTION_USER_RETRY_MAX, userRetryMax);
868        json.put(JsonTags.WORKFLOW_ACTION_CRED, cred);
869        return json;
870    }
871
872    @Override
873    public String getId() {
874        return id;
875    }
876
877    public void setId(String id) {
878        this.id = id;
879    }
880
881    public Timestamp getCreatedTimestamp() {
882        return createdTimeTS;
883    }
884
885    public Date getCreatedTime() {
886        return DateUtils.toDate(createdTimeTS);
887    }
888
889    public void setCreatedTime(Date createdTime) {
890        this.createdTimeTS = DateUtils.convertDateToTimestamp(createdTime);
891    }
892
893    @Override
894    public String getName() {
895        return name;
896    }
897
898    public void setName(String name) {
899        this.name = name;
900    }
901
902    @Override
903    public String getCred() {
904        return cred;
905    }
906
907    public void setCred(String cred) {
908        this.cred = cred;
909    }
910
911    @Override
912    public String getType() {
913        return type;
914    }
915
916    public void setType(String type) {
917        this.type = type;
918    }
919
920    @Override
921    public String getConf() {
922        return conf == null ? null : conf.getString();
923    }
924
925    public void setConf(String conf) {
926        if (this.conf == null) {
927            this.conf = new StringBlob(conf);
928        }
929        else {
930            this.conf.setString(conf);
931        }
932    }
933
934    public void setConfBlob(StringBlob conf) {
935        this.conf = conf;
936    }
937
938    public StringBlob getConfBlob() {
939        return conf;
940    }
941
942    @Override
943    public int getRetries() {
944        return retries;
945    }
946
947    public void setRetries(int retries) {
948        this.retries = retries;
949    }
950
951    @Override
952    public int getUserRetryCount() {
953        return userRetryCount;
954    }
955
956    public void setUserRetryCount(int retryCount) {
957        this.userRetryCount = retryCount;
958    }
959
960    public void incrmentUserRetryCount() {
961        this.userRetryCount++;
962    }
963
964    @Override
965    public int getUserRetryMax() {
966        return userRetryMax;
967    }
968
969    /**
970     * Set user retry max
971     *
972     * @param retryMax
973     */
974    public void setUserRetryMax(int retryMax) {
975        this.userRetryMax = retryMax;
976    }
977
978    @Override
979    public int getUserRetryInterval() {
980        return userRetryInterval;
981    }
982
983    public void setUserRetryInterval(int retryInterval) {
984        this.userRetryInterval = retryInterval;
985    }
986
987    @Override
988    public String getTransition() {
989        return transition;
990    }
991
992    /**
993     * Set transition
994     *
995     * @param transition
996     */
997    public void setTransition(String transition) {
998        this.transition = transition;
999    }
1000
1001    @Override
1002    public String getData() {
1003        return data == null ? null : data.getString();
1004    }
1005
1006    /**
1007     * Set data
1008     *
1009     * @param data
1010     */
1011    public void setData(String data) {
1012        if (this.data == null) {
1013            this.data = new StringBlob(data);
1014        }
1015        else {
1016            this.data.setString(data);
1017        }
1018    }
1019
1020    public void setDataBlob(StringBlob data) {
1021        this.data = data;
1022    }
1023
1024    public StringBlob getDataBlob() {
1025        return data;
1026    }
1027
1028    @Override
1029    public String getStats() {
1030        return stats == null ? null : stats.getString();
1031    }
1032
1033    /**
1034     * Set stats
1035     *
1036     * @param stats
1037     */
1038    public void setStats(String stats) {
1039        if (this.stats == null) {
1040            this.stats = new StringBlob(stats);
1041        }
1042        else {
1043            this.stats.setString(stats);
1044        }
1045    }
1046
1047    public void setStatsBlob(StringBlob stats) {
1048        this.stats = stats;
1049    }
1050
1051    public StringBlob getStatsBlob() {
1052        return this.stats;
1053    }
1054
1055    @Override
1056    public String getExternalId() {
1057        return externalId;
1058    }
1059
1060    /**
1061     * Set external Id
1062     *
1063     * @param externalId
1064     */
1065    public void setExternalId(String externalId) {
1066        this.externalId = externalId;
1067    }
1068
1069    @Override
1070    public String getExternalStatus() {
1071        return externalStatus;
1072    }
1073
1074    /**
1075     * Set external status
1076     *
1077     * @param externalStatus
1078     */
1079    public void setExternalStatus(String externalStatus) {
1080        this.externalStatus = externalStatus;
1081    }
1082
1083    @Override
1084    public String getTrackerUri() {
1085        return trackerUri;
1086    }
1087
1088    /**
1089     * Set tracker uri
1090     *
1091     * @param trackerUri
1092     */
1093    public void setTrackerUri(String trackerUri) {
1094        this.trackerUri = trackerUri;
1095    }
1096
1097    @Override
1098    public String getConsoleUrl() {
1099        return consoleUrl;
1100    }
1101
1102    /**
1103     * Set console URL
1104     *
1105     * @param consoleUrl
1106     */
1107    public void setConsoleUrl(String consoleUrl) {
1108        this.consoleUrl = consoleUrl;
1109    }
1110
1111    @Override
1112    public String getErrorCode() {
1113        return errorCode;
1114    }
1115
1116    @Override
1117    public String getErrorMessage() {
1118        return errorMessage;
1119    }
1120
1121    /**
1122     * Set the error Info
1123     *
1124     * @param errorCode
1125     * @param errorMessage
1126     */
1127    public void setErrorInfo(String errorCode, String errorMessage) {
1128        this.errorCode = errorCode;
1129        if (errorMessage != null && errorMessage.length() > 500) {
1130            errorMessage = errorMessage.substring(0, 500);
1131        }
1132        this.errorMessage = errorMessage;
1133    }
1134
1135    @Override
1136    public String toString() {
1137        return MessageFormat.format("Action name[{0}] status[{1}]", getName(), getStatus());
1138    }
1139
1140    /**
1141     * Convert a nodes list into a JSONArray.
1142     *
1143     * @param nodes nodes list.
1144     * @param timeZoneId time zone to use for dates in the JSON array.
1145     * @return the corresponding JSON array.
1146     */
1147    @SuppressWarnings("unchecked")
1148    public static JSONArray toJSONArray(List<WorkflowActionBean> nodes, String timeZoneId) {
1149        JSONArray array = new JSONArray();
1150        for (WorkflowActionBean node : nodes) {
1151            array.add(node.toJSONObject(timeZoneId));
1152        }
1153        return array;
1154    }
1155
1156}