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