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;
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;
037import javax.persistence.Transient;
038
039import org.apache.hadoop.io.Writable;
040import org.apache.oozie.client.CoordinatorAction;
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.coord.input.dependency.CoordInputDependency;
045import org.apache.oozie.coord.input.dependency.CoordInputDependencyFactory;
046import org.apache.oozie.util.DateUtils;
047import org.apache.oozie.util.WritableUtils;
048import org.apache.openjpa.persistence.jdbc.Index;
049import org.apache.openjpa.persistence.jdbc.Strategy;
050import org.json.simple.JSONArray;
051import org.json.simple.JSONObject;
052
053
054@Entity
055@NamedQueries({
056
057        @NamedQuery(name = "UPDATE_COORD_ACTION", query = "update CoordinatorActionBean w set w.actionNumber = :actionNumber,"
058                + " w.actionXml = :actionXml, w.consoleUrl = :consoleUrl, w.createdConf = :createdConf, w.errorCode = :errorCode,"
059                + " w.errorMessage = :errorMessage, w.externalStatus = :externalStatus, w.missingDependencies "
060                + "= :missingDependencies, w.runConf = :runConf, w.timeOut = :timeOut, w.trackerUri = :trackerUri, w.type "
061                + "= :type, w.createdTimestamp = :createdTime, w.externalId = :externalId, w.jobId = :jobId,"
062                + " w.lastModifiedTimestamp = :lastModifiedTime, w.nominalTimestamp = :nominalTime, w.slaXml = :slaXml,"
063                + " w.statusStr = :status where w.id = :id"),
064
065        @NamedQuery(name = "UPDATE_COORD_ACTION_MIN", query = "update CoordinatorActionBean w set w.actionXml = :actionXml,"
066                + " w.missingDependencies = :missingDependencies, w.lastModifiedTimestamp = :lastModifiedTime, w.statusStr "
067                + "= :status where w.id = :id"),
068        // Query to update the action status, pending status and last modified time stamp of a Coordinator action
069        @NamedQuery(name = "UPDATE_COORD_ACTION_STATUS_PENDING_TIME", query = "update CoordinatorActionBean w set w.statusStr"
070                + " =:status, w.pending =:pending, w.lastModifiedTimestamp = :lastModifiedTime where w.id = :id"),
071        // Update query for InputCheck
072        @NamedQuery(name = "UPDATE_COORD_ACTION_FOR_INPUTCHECK", query = "update CoordinatorActionBean w set w.statusStr "
073                + "= :status, w.lastModifiedTimestamp = :lastModifiedTime, w.actionXml = :actionXml, w.missingDependencies "
074                + "= :missingDependencies where w.id = :id"),
075        // Update query for Push-based missing dependency check
076        @NamedQuery(name = "UPDATE_COORD_ACTION_FOR_PUSH_INPUTCHECK", query = "update CoordinatorActionBean w set w.statusStr "
077                + "= :status, w.lastModifiedTimestamp = :lastModifiedTime,  w.actionXml = :actionXml, w.pushMissingDependencies "
078                + "= :pushMissingDependencies where w.id = :id"),
079        // Update query for Push-based missing dependency check
080        @NamedQuery(name = "UPDATE_COORD_ACTION_DEPENDENCIES", query = "update CoordinatorActionBean w set w.missingDependencies"
081                + " = :missingDependencies, w.pushMissingDependencies = :pushMissingDependencies where w.id = :id"),
082        // Update query for Start
083        @NamedQuery(name = "UPDATE_COORD_ACTION_FOR_START", query = "update CoordinatorActionBean w set w.statusStr =:status,"
084                + " w.lastModifiedTimestamp = :lastModifiedTime, w.runConf = :runConf, w.externalId = :externalId, w.pending "
085                + "= :pending, w.errorCode = :errorCode, w.errorMessage = :errorMessage  where w.id = :id"),
086
087        @NamedQuery(name = "UPDATE_COORD_ACTION_FOR_MODIFIED_DATE", query = "update CoordinatorActionBean w set"
088                + " w.lastModifiedTimestamp = :lastModifiedTime where w.id = :id"),
089
090        @NamedQuery(name = "UPDATE_COORD_ACTION_RERUN", query = "update CoordinatorActionBean w set w.actionXml =:actionXml,"
091                + " w.statusStr = :status, w.externalId = :externalId, w.externalStatus = :externalStatus, w.rerunTimestamp "
092                + "= :rerunTime, w.lastModifiedTimestamp = :lastModifiedTime, w.createdTimestamp = :createdTime, w.createdConf "
093                + "= :createdConf, w.runConf = :runConf, w.missingDependencies = :missingDependencies, w.pushMissingDependencies "
094                + "= :pushMissingDependencies, w.errorCode = :errorCode, w.errorMessage = :errorMessage where w.id = :id"),
095
096        @NamedQuery(name = "DELETE_COMPLETED_ACTIONS_FOR_COORDINATOR", query = "delete from CoordinatorActionBean a where a.jobId"
097                + " = :jobId and (a.statusStr = 'SUCCEEDED' OR a.statusStr = 'FAILED' OR a.statusStr= 'KILLED')"),
098
099        @NamedQuery(name = "DELETE_ACTIONS_FOR_LONG_RUNNING_COORDINATOR", query = "delete from CoordinatorActionBean a where a.id"
100                + " IN (:actionId)"),
101
102        @NamedQuery(name = "DELETE_UNSCHEDULED_ACTION", query = "delete from CoordinatorActionBean a where a.id = :id "
103                + "and (a.statusStr = 'WAITING' OR a.statusStr = 'READY')"),
104
105        @NamedQuery(name = "GET_COORD_ACTIONS_FOR_COORDINATOR", query = "select a.id from CoordinatorActionBean a where a.jobId"
106                + " = :jobId"),
107
108        // Query used by XTestcase to setup tables
109        @NamedQuery(name = "GET_COORD_ACTIONS", query = "select OBJECT(w) from CoordinatorActionBean w"),
110        // Select query used only by test cases
111        @NamedQuery(name = "GET_COORD_ACTION", query = "select OBJECT(a) from CoordinatorActionBean a where a.id = :id"),
112
113        // Select query used by SLAService on restart
114        @NamedQuery(name = "GET_COORD_ACTION_FOR_SLA", query = "select a.id, a.jobId, a.statusStr, a.externalId,"
115                + " a.lastModifiedTimestamp from CoordinatorActionBean a where a.id = :id"),
116        // Select query used by ActionInfo command
117        @NamedQuery(name = "GET_COORD_ACTION_FOR_INFO", query = "select a.id, a.jobId, a.actionNumber, a.consoleUrl, a.errorCode,"
118                + " a.errorMessage, a.externalId, a.externalStatus, a.trackerUri, a.createdTimestamp, a.nominalTimestamp,"
119                + " a.statusStr, a.lastModifiedTimestamp, a.missingDependencies, a.pushMissingDependencies "
120                + "from CoordinatorActionBean a where a.id = :id"),
121        // Select Query used by Timeout and skip commands
122        @NamedQuery(name = "GET_COORD_ACTION_FOR_TIMEOUT", query = "select a.id, a.jobId, a.statusStr, a.runConf, a.pending,"
123                + " a.nominalTimestamp, a.createdTimestamp from CoordinatorActionBean a where a.id = :id"),
124        // Select query used by InputCheck command
125        @NamedQuery(name = "GET_COORD_ACTION_FOR_INPUTCHECK", query = "select a.id, a.actionNumber, a.jobId, a.statusStr,"
126                + " a.runConf, a.nominalTimestamp, a.createdTimestamp, a.actionXml, a.missingDependencies,"
127                + " a.pushMissingDependencies, a.timeOut, a.externalId from CoordinatorActionBean a where a.id = :id"),
128        // Select query used by CoordActionUpdate command
129        @NamedQuery(name = "GET_COORD_ACTION_FOR_EXTERNALID", query = "select a.id, a.jobId, a.statusStr, a.pending,"
130                + " a.externalId, a.lastModifiedTimestamp, a.slaXml, a.nominalTimestamp, a.createdTimestamp "
131                + "from CoordinatorActionBean a where a.externalId = :externalId"),
132        // Select query used by Check command
133        @NamedQuery(name = "GET_COORD_ACTION_FOR_CHECK", query = "select a.id, a.jobId, a.statusStr, a.pending, a.externalId,"
134                + " a.lastModifiedTimestamp, a.slaXml, a.nominalTimestamp, a.createdTimestamp from CoordinatorActionBean a"
135                + " where a.id = :id"),
136        // Select query used by Start command
137        @NamedQuery(name = "GET_COORD_ACTION_FOR_START", query = "select a.id, a.jobId, a.statusStr, a.pending, a.createdConf,"
138                + " a.slaXml, a.actionXml, a.externalId, a.errorMessage, a.errorCode, a.nominalTimestamp, a.createdTimestamp "
139                + "from CoordinatorActionBean a where a.id = :id"),
140
141        @NamedQuery(name = "GET_COORD_ACTIONS_FOR_JOB_FIFO", query = "select a.id, a.actionNumber, a.jobId, a.statusStr,"
142                + " a.pending, a.nominalTimestamp, a.createdTimestamp from CoordinatorActionBean a where a.jobId = :jobId "
143                + "AND a.statusStr = 'READY' order by a.nominalTimestamp"),
144
145        @NamedQuery(name = "GET_COORD_ACTIONS_FOR_JOB_LIFO", query = "select a.id, a.actionNumber, a.jobId, a.statusStr,"
146                + " a.pending, a.nominalTimestamp, a.createdTimestamp from CoordinatorActionBean a where a.jobId = :jobId "
147                + "AND a.statusStr = 'READY' order by a.nominalTimestamp desc"),
148
149        @NamedQuery(name = "GET_COORD_RUNNING_ACTIONS_COUNT", query = "select count(a) from CoordinatorActionBean a where a.jobId"
150                + " = :jobId AND (a.statusStr = 'RUNNING' OR a.statusStr='SUBMITTED')"),
151
152        @NamedQuery(name = "GET_COORD_ACTIONS_COUNT_BY_JOBID", query = "select count(a) from CoordinatorActionBean a "
153                + "where a.jobId = :jobId"),
154
155        @NamedQuery(name = "GET_COORD_ACTIVE_ACTIONS_COUNT_BY_JOBID", query = "select count(a) from CoordinatorActionBean a"
156                + " where a.jobId = :jobId AND a.statusStr = 'WAITING'"),
157
158        @NamedQuery(name = "GET_COORD_ACTIONS_PENDING_FALSE_COUNT", query = "select count(a) from CoordinatorActionBean a "
159                + "where a.jobId = :jobId AND a.pending = 0 AND (a.statusStr = 'SUSPENDED' OR a.statusStr = 'TIMEDOUT' "
160                + "OR a.statusStr = 'SUCCEEDED' OR a.statusStr = 'KILLED' OR a.statusStr = 'FAILED')"),
161
162        @NamedQuery(name = "GET_COORD_ACTIONS_PENDING_FALSE_STATUS_COUNT", query = "select count(a) from CoordinatorActionBean a"
163                + " where a.jobId = :jobId AND a.pending = 0 AND a.statusStr = :status"),
164
165        @NamedQuery(name = "GET_ACTIONS_FOR_COORD_JOB", query = "select count(a) from CoordinatorActionBean a where a.jobId"
166                + " = :jobId"),
167        // Query to retrieve Coordinator actions sorted by nominal time
168        @NamedQuery(name = "GET_ACTIONS_FOR_COORD_JOB_ORDER_BY_NOMINAL_TIME", query = "select a.id, a.actionNumber, a.consoleUrl,"
169                + " a.errorCode, a.errorMessage, a.externalId, a.externalStatus, a.jobId, a.trackerUri, a.createdTimestamp,"
170                + " a.nominalTimestamp, a.statusStr, a.lastModifiedTimestamp, a.missingDependencies, a.pushMissingDependencies,"
171                + " a.timeOut from CoordinatorActionBean a where a.jobId = :jobId order by a.nominalTimestamp"),
172        // Query to maintain backward compatibility for coord job info command
173        @NamedQuery(name = "GET_ALL_COLS_FOR_ACTIONS_FOR_COORD_JOB_ORDER_BY_NOMINAL_TIME", query = "select OBJECT(a) "
174                + "from CoordinatorActionBean a where a.jobId = :jobId order by a.nominalTimestamp"),
175        // Query to retrieve action id, action status, pending status and external Id of not completed Coordinator actions
176        @NamedQuery(name = "GET_COORD_ACTIONS_NOT_COMPLETED", query = "select a.id, a.statusStr, a.pending, a.externalId,"
177                + " a.pushMissingDependencies, a.nominalTimestamp, a.createdTimestamp, a.jobId from CoordinatorActionBean a"
178                + " where a.jobId = :jobId AND a.statusStr <> 'FAILED' AND a.statusStr <> 'TIMEDOUT' AND a.statusStr "
179                + "<> 'SUCCEEDED' AND a.statusStr <> 'KILLED' AND a.statusStr <> 'IGNORED'"),
180
181        // Query to retrieve action id, action status, pending status and external Id of running Coordinator actions
182        @NamedQuery(name = "GET_COORD_ACTIONS_RUNNING", query = "select a.id, a.statusStr, a.pending, a.externalId,"
183                + " a.nominalTimestamp, a.createdTimestamp from CoordinatorActionBean a where a.jobId = :jobId "
184                + "and a.statusStr = 'RUNNING'"),
185
186        // Query to retrieve action id, action status, pending status and external Id of suspended Coordinator actions
187        @NamedQuery(name = "GET_COORD_ACTIONS_SUSPENDED", query = "select a.id, a.statusStr, a.pending, a.externalId,"
188                + " a.nominalTimestamp, a.createdTimestamp from CoordinatorActionBean a where a.jobId = :jobId "
189                + "and a.statusStr = 'SUSPENDED'"),
190
191        // Query to retrieve count of Coordinator actions which are pending
192        @NamedQuery(name = "GET_COORD_ACTIONS_PENDING_COUNT", query = "select count(a) from CoordinatorActionBean a where a.jobId"
193                + " = :jobId AND a.pending > 0"),
194
195        // Query to retrieve status of Coordinator actions
196        @NamedQuery(name = "GET_COORD_ACTIONS_STATUS_UNIGNORED", query = "select a.statusStr, a.pending "
197                + "from CoordinatorActionBean a where a.jobId = :jobId AND a.statusStr <> 'IGNORED'"),
198
199        // Query to retrieve status of Coordinator actions
200        @NamedQuery(name = "GET_COORD_ACTION_STATUS", query = "select a.statusStr from CoordinatorActionBean a where a.id = :id"),
201
202        @NamedQuery(name = "GET_COORD_ACTION_FOR_COORD_JOB_BY_ACTION_NUMBER", query = "select a.id from CoordinatorActionBean a"
203                + " where a.jobId = :jobId AND a.actionNumber = :actionNumber"),
204
205        @NamedQuery(name = "GET_COORD_ACTIONS_BY_LAST_MODIFIED_TIME", query = "select a.jobId from CoordinatorActionBean a "
206                + "where a.lastModifiedTimestamp >= :lastModifiedTime"),
207
208        //Used by coordinator store only
209        @NamedQuery(name = "GET_RUNNING_ACTIONS_FOR_COORD_JOB", query = "select OBJECT(a) from CoordinatorActionBean a "
210                + "where a.jobId = :jobId AND a.statusStr = 'RUNNING'"),
211
212        @NamedQuery(name = "GET_RUNNING_ACTIONS_OLDER_THAN", query = "select a.id from CoordinatorActionBean a where a.statusStr"
213                + " = 'RUNNING' AND a.lastModifiedTimestamp <= :lastModifiedTime"),
214
215        @NamedQuery(name = "GET_COORD_ACTIONS_WAITING_READY_SUBMITTED_OLDER_THAN", query = "select a.id, a.jobId, a.statusStr,"
216                + " a.externalId, a.pushMissingDependencies from CoordinatorActionBean a where (a.statusStr = 'WAITING' "
217                + "OR a.statusStr = 'SUBMITTED' OR a.statusStr = 'READY') AND a.lastModifiedTimestamp <= :lastModifiedTime "
218                + "and a.nominalTimestamp <= :currentTime and a.jobId in ( select w.id from CoordinatorJobBean w"
219                + " where w.statusStr = 'RUNNING' or w.statusStr = 'RUNNINGWITHERROR')"),
220
221        @NamedQuery(name = "GET_COORD_ACTIONS_FOR_RECOVERY_OLDER_THAN", query = "select a.id, a.jobId, a.statusStr, a.externalId,"
222                + " a.pending from CoordinatorActionBean a where a.pending > 0 AND (a.statusStr = 'SUSPENDED' OR a.statusStr "
223                + "= 'KILLED' OR a.statusStr = 'RUNNING') AND a.lastModifiedTimestamp <= :lastModifiedTime"),
224        // Select query used by rerun, requires almost all columns so select * is used
225        @NamedQuery(name = "GET_TERMINATED_ACTIONS_FOR_DATES", query = "select OBJECT(a) from CoordinatorActionBean a "
226                + "where a.jobId = :jobId AND (a.statusStr = 'TIMEDOUT' OR a.statusStr = 'SUCCEEDED' OR a.statusStr = 'KILLED' "
227                + "OR a.statusStr = 'FAILED' OR a.statusStr = 'IGNORED') AND a.nominalTimestamp >= :startTime "
228                + "AND a.nominalTimestamp <= :endTime"),
229        // Select query used by log
230        @NamedQuery(name = "GET_TERMINATED_ACTION_IDS_FOR_DATES", query = "select a.id from CoordinatorActionBean a where a.jobId"
231                + " = :jobId AND (a.statusStr = 'TIMEDOUT' OR a.statusStr = 'SUCCEEDED' OR a.statusStr = 'KILLED' OR a.statusStr"
232                + " = 'FAILED') AND a.nominalTimestamp >= :startTime AND a.nominalTimestamp <= :endTime"),
233        // Select query used by rerun, requires almost all columns so select * is used
234        @NamedQuery(name = "GET_ACTION_FOR_NOMINALTIME", query = "select OBJECT(a) from CoordinatorActionBean a where a.jobId "
235                + "= :jobId AND a.nominalTimestamp = :nominalTime"),
236
237        @NamedQuery(name = "GET_ACTIVE_ACTIONS_FOR_DATES", query = "select a.id, a.jobId, a.statusStr, a.externalId, a.pending,"
238                + " a.nominalTimestamp, a.createdTimestamp from CoordinatorActionBean a where a.jobId = :jobId AND (a.statusStr "
239                + "= 'WAITING' OR a.statusStr = 'READY' OR a.statusStr = 'SUBMITTED' OR a.statusStr = 'RUNNING'  OR a.statusStr "
240                + "= 'SUSPENDED') AND a.nominalTimestamp >= :startTime AND a.nominalTimestamp <= :endTime"),
241
242        @NamedQuery(name = "GET_COORD_ACTIONS_COUNT", query = "select count(w) from CoordinatorActionBean w"),
243
244        @NamedQuery(name = "GET_COORD_ACTIONS_COUNT_RUNNING_FOR_RANGE", query = "select count(w) from CoordinatorActionBean w"
245                + " where w.statusStr = 'RUNNING' and w.jobId= :jobId and w.id >= :startAction AND w.id <= :endAction"),
246
247        @NamedQuery(name = "GET_COORD_ACTIONS_MAX_MODIFIED_DATE_FOR_RANGE", query = "select max(w.lastModifiedTimestamp) "
248                + "from CoordinatorActionBean w where w.jobId= :jobId and w.id >= :startAction AND w.id <= :endAction"),
249
250         @NamedQuery(name = "GET_ACTIVE_ACTIONS_IDS_FOR_SLA_CHANGE", query = "select a.id, a.nominalTimestamp,"
251                 + " a.createdTimestamp, a.actionXml  from CoordinatorActionBean a where a.id in (:ids)"
252                 + " and (a.statusStr <> 'FAILED' AND a.statusStr <> 'KILLED' AND a.statusStr <> 'SUCCEEDED' AND a.statusStr "
253                 + "<> 'TIMEDOUT'  AND a.statusStr <> 'IGNORED')"),
254
255         @NamedQuery(name = "GET_ACTIVE_ACTIONS_JOBID_FOR_SLA_CHANGE", query = "select a.id, a.nominalTimestamp,"
256                 + " a.createdTimestamp, a.actionXml  from CoordinatorActionBean a where a.jobId = :jobId and (a.statusStr "
257                 + "<> 'FAILED' AND a.statusStr <> 'KILLED' AND a.statusStr <> 'SUCCEEDED' AND a.statusStr <> 'TIMEDOUT'  "
258                 + "AND a.statusStr <> 'IGNORED')")
259 })
260
261@Table(name = "COORD_ACTIONS")
262public class CoordinatorActionBean implements
263        Writable,CoordinatorAction,JsonBean {
264
265    @Id
266    private String id;
267
268    @Basic
269    @Index
270    @Column(name = "job_id")
271    private String jobId;
272
273    @Basic
274    @Index
275    @Column(name = "status")
276    private String statusStr = CoordinatorAction.Status.WAITING.toString();
277
278    @Basic
279    @Index
280    @Column(name = "nominal_time")
281    private java.sql.Timestamp nominalTimestamp = null;
282
283    @Basic
284    @Index
285    @Column(name = "last_modified_time")
286    private java.sql.Timestamp lastModifiedTimestamp = null;
287
288    @Basic
289    @Index
290    @Column(name = "created_time")
291    private java.sql.Timestamp createdTimestamp = null;
292
293    @Basic
294    @Index
295    @Column(name = "rerun_time")
296    private java.sql.Timestamp rerunTimestamp = null;
297
298    @Basic
299    @Index
300    @Column(name = "external_id")
301    private String externalId;
302
303    @Basic
304    @Column(name = "sla_xml")
305    @Lob
306    @Strategy("org.apache.oozie.executor.jpa.StringBlobValueHandler")
307    private StringBlob slaXml = null;
308
309    @Basic
310    @Column(name = "pending")
311    private int pending = 0;
312
313    @Basic
314    @Column(name = "job_type")
315    private String type;
316
317    @Basic
318    @Column(name = "action_number")
319    private int actionNumber;
320
321    @Basic
322    @Column(name = "created_conf")
323    @Lob
324    @Strategy("org.apache.oozie.executor.jpa.StringBlobValueHandler")
325    private StringBlob createdConf;
326
327    @Basic
328    @Column(name = "time_out")
329    private int timeOut = 0;
330
331    @Basic
332    @Column(name = "run_conf")
333    @Lob
334    @Strategy("org.apache.oozie.executor.jpa.StringBlobValueHandler")
335    private StringBlob runConf;
336
337    @Basic
338    @Column(name = "action_xml")
339    @Lob
340    @Strategy("org.apache.oozie.executor.jpa.StringBlobValueHandler")
341    private StringBlob actionXml;
342
343    @Basic
344    @Column(name = "missing_dependencies")
345    @Lob
346    @Strategy("org.apache.oozie.executor.jpa.StringBlobValueHandler")
347    private StringBlob missingDependencies;
348
349    @Basic
350    @Column(name = "push_missing_dependencies")
351    @Lob
352    @Strategy("org.apache.oozie.executor.jpa.StringBlobValueHandler")
353    private StringBlob pushMissingDependencies;
354
355    @Basic
356    @Column(name = "external_status")
357    private String externalStatus;
358
359    @Basic
360    @Column(name = "tracker_uri")
361    private String trackerUri;
362
363    @Basic
364    @Column(name = "console_url")
365    private String consoleUrl;
366
367    @Basic
368    @Column(name = "error_code")
369    private String errorCode;
370
371    @Basic
372    @Column(name = "error_message")
373    private String errorMessage;
374
375    @SuppressWarnings("unchecked")
376    public JSONObject toJSONObject() {
377        return toJSONObject("GMT");
378    }
379
380    @Transient
381    private CoordInputDependency coordPushInputDependency;
382
383    @Transient
384    private CoordInputDependency coordPullInputDependency;
385
386
387    public CoordinatorActionBean() {
388    }
389
390    /**
391     * Serialize the coordinator bean to a data output.
392     *
393     * @param dataOutput data output.
394     * @throws IOException thrown if the coordinator bean could not be
395     *         serialized.
396     */
397    @Override
398    public void write(DataOutput dataOutput) throws IOException {
399        WritableUtils.writeStr(dataOutput, getJobId());
400        WritableUtils.writeStr(dataOutput, getType());
401        WritableUtils.writeStr(dataOutput, getId());
402        WritableUtils.writeStr(dataOutput, getCreatedConf());
403        WritableUtils.writeStr(dataOutput, getStatus().toString());
404        dataOutput.writeInt(getActionNumber());
405        WritableUtils.writeStr(dataOutput, getRunConf());
406        WritableUtils.writeStr(dataOutput, getExternalStatus());
407        WritableUtils.writeStr(dataOutput, getTrackerUri());
408        WritableUtils.writeStr(dataOutput, getConsoleUrl());
409        WritableUtils.writeStr(dataOutput, getErrorCode());
410        WritableUtils.writeStr(dataOutput, getErrorMessage());
411        dataOutput.writeLong((getCreatedTime() != null) ? getCreatedTime().getTime() : -1);
412        dataOutput.writeLong((getLastModifiedTime() != null) ? getLastModifiedTime().getTime() : -1);
413    }
414
415    /**
416     * Deserialize a coordinator bean from a data input.
417     *
418     * @param dataInput data input.
419     * @throws IOException thrown if the workflow bean could not be
420     *         deserialized.
421     */
422    @Override
423    public void readFields(DataInput dataInput) throws IOException {
424        setJobId(WritableUtils.readStr(dataInput));
425        setType(WritableUtils.readStr(dataInput));
426        setId(WritableUtils.readStr(dataInput));
427        setCreatedConf(WritableUtils.readStr(dataInput));
428        setStatus(CoordinatorAction.Status.valueOf(WritableUtils.readStr(dataInput)));
429        setActionNumber(dataInput.readInt());
430        setRunConf(WritableUtils.readStr(dataInput));
431        setExternalStatus(WritableUtils.readStr(dataInput));
432        setTrackerUri(WritableUtils.readStr(dataInput));
433        setConsoleUrl(WritableUtils.readStr(dataInput));
434        setErrorCode(WritableUtils.readStr(dataInput));
435        setErrorMessage(WritableUtils.readStr(dataInput));
436        long d = dataInput.readLong();
437        if (d != -1) {
438            setCreatedTime(new Date(d));
439        }
440        d = dataInput.readLong();
441        if (d != -1) {
442            setLastModifiedTime(new Date(d));
443        }
444    }
445
446    @Override
447    public String getJobId() {
448        return this.jobId;
449    }
450
451    public void setJobId(String id) {
452        this.jobId = id;
453    }
454
455    @Override
456    public Status getStatus() {
457        return Status.valueOf(statusStr);
458    }
459
460    /**
461     * Return the status in string
462     * @return statusStr
463     */
464    public String getStatusStr() {
465        return statusStr;
466    }
467
468    public void setStatus(Status status) {
469        this.statusStr = status.toString();
470    }
471
472    public void setStatusStr(String statusStr) {
473        this.statusStr = statusStr;
474    }
475
476    public void setCreatedTime(Date createdTime) {
477        this.createdTimestamp = DateUtils.convertDateToTimestamp(createdTime);
478    }
479
480    public void setRerunTime(Date rerunTime) {
481        this.rerunTimestamp = DateUtils.convertDateToTimestamp(rerunTime);
482    }
483
484    public void setNominalTime(Date nominalTime) {
485        this.nominalTimestamp = DateUtils.convertDateToTimestamp(nominalTime);
486    }
487
488    public void setLastModifiedTime(Date lastModifiedTime) {
489        this.lastModifiedTimestamp = DateUtils.convertDateToTimestamp(lastModifiedTime);
490    }
491
492    public Date getCreatedTime() {
493        return DateUtils.toDate(createdTimestamp);
494    }
495
496    public Timestamp getCreatedTimestamp() {
497        return createdTimestamp;
498    }
499
500    public Date getRerunTime() {
501        return DateUtils.toDate(rerunTimestamp);
502    }
503
504    public Timestamp getRerunTimestamp() {
505        return rerunTimestamp;
506    }
507
508    @Override
509    public Date getLastModifiedTime() {
510        return DateUtils.toDate(lastModifiedTimestamp);
511    }
512
513    public Timestamp getLastModifiedTimestamp() {
514        return lastModifiedTimestamp;
515    }
516
517    @Override
518    public Date getNominalTime() {
519        return DateUtils.toDate(nominalTimestamp);
520    }
521
522    public Timestamp getNominalTimestamp() {
523        return nominalTimestamp;
524    }
525
526    @Override
527    public String getExternalId() {
528        return externalId;
529    }
530
531    public void setExternalId(String externalId) {
532        this.externalId = externalId;
533    }
534
535    public StringBlob getSlaXmlBlob() {
536        return slaXml;
537    }
538
539    public void setSlaXmlBlob(StringBlob slaXml) {
540        this.slaXml = slaXml;
541    }
542
543    public String getSlaXml() {
544        return slaXml == null ? null : slaXml.getString();
545    }
546
547    public void setSlaXml(String slaXml) {
548        if (this.slaXml == null) {
549            this.slaXml = new StringBlob(slaXml);
550        }
551        else {
552            this.slaXml.setString(slaXml);
553        }
554    }
555
556    /**
557     * @return true if in terminal status
558     */
559    public boolean isTerminalStatus() {
560        boolean isTerminal = true;
561        switch (getStatus()) {
562            case WAITING:
563            case READY:
564            case SUBMITTED:
565            case RUNNING:
566            case SUSPENDED:
567                isTerminal = false;
568                break;
569            default:
570                isTerminal = true;
571                break;
572        }
573        return isTerminal;
574    }
575
576    /**
577     * Return if the action is complete with failure.
578     *
579     * @return if the action is complete with failure.
580     */
581    public boolean isTerminalWithFailure() {
582        boolean result = false;
583        switch (getStatus()) {
584            case FAILED:
585            case KILLED:
586            case TIMEDOUT:
587                result = true;
588        }
589        return result;
590    }
591
592    /**
593     * Set some actions are in progress for particular coordinator action.
594     *
595     * @param pending set pending to true
596     */
597    public void setPending(int pending) {
598        this.pending = pending;
599    }
600
601    /**
602     * increment pending and return it
603     *
604     * @return pending
605     */
606    public int incrementAndGetPending() {
607        this.pending++;
608        return pending;
609    }
610
611    /**
612     * decrement pending and return it
613     *
614     * @return pending
615     */
616    public int decrementAndGetPending() {
617        this.pending = Math.max(this.pending - 1, 0);
618        return pending;
619    }
620
621    /**
622     * Get some actions are in progress for particular bundle action.
623     *
624     * @return pending
625     */
626    public int getPending() {
627        return this.pending;
628    }
629
630    /**
631     * Return if the action is pending.
632     *
633     * @return if the action is pending.
634     */
635    public boolean isPending() {
636        return pending > 0 ? true : false;
637    }
638
639    @Override
640    public String getId() {
641        return id;
642    }
643
644    public void setId(String id) {
645        this.id = id;
646    }
647
648    public String getType() {
649        return type;
650    }
651
652    public void setType(String type) {
653        this.type = type;
654    }
655
656    public void setActionNumber(int actionNumber) {
657        this.actionNumber = actionNumber;
658    }
659
660    @Override
661    public int getActionNumber() {
662        return actionNumber;
663    }
664
665    @Override
666    public String getCreatedConf() {
667        return createdConf == null ? null : createdConf.getString();
668    }
669
670    public void setCreatedConf(String createdConf) {
671        if (this.createdConf == null) {
672            this.createdConf = new StringBlob(createdConf);
673        }
674        else {
675            this.createdConf.setString(createdConf);
676        }
677    }
678
679    public void setCreatedConfBlob(StringBlob createdConf) {
680        this.createdConf = createdConf;
681    }
682
683    public StringBlob getCreatedConfBlob() {
684        return createdConf;
685    }
686
687    public void setRunConf(String runConf) {
688        if (this.runConf == null) {
689            this.runConf = new StringBlob(runConf);
690        }
691        else {
692            this.runConf.setString(runConf);
693        }
694    }
695
696    @Override
697    public String getRunConf() {
698        return runConf == null ? null : runConf.getString();
699    }
700
701    public void setRunConfBlob(StringBlob runConf) {
702        this.runConf = runConf;
703    }
704
705    public StringBlob getRunConfBlob() {
706        return runConf;
707    }
708
709
710    public void setMissingDependencies(String missingDependencies) {
711        if (this.missingDependencies == null) {
712            this.missingDependencies = new StringBlob(missingDependencies);
713        }
714        else {
715            this.missingDependencies.setString(missingDependencies);
716        }
717    }
718
719    @Override
720    public String getMissingDependencies() {
721        return missingDependencies == null ? null : missingDependencies.getString();
722    }
723
724    public void setMissingDependenciesBlob(StringBlob missingDependencies) {
725        this.missingDependencies = missingDependencies;
726    }
727
728    public StringBlob getMissingDependenciesBlob() {
729        return missingDependencies;
730    }
731
732    @Override
733    public String getPushMissingDependencies() {
734        return pushMissingDependencies == null ? null : pushMissingDependencies.getString();
735    }
736
737    public void setPushMissingDependencies(String pushMissingDependencies) {
738        if (this.pushMissingDependencies == null) {
739            this.pushMissingDependencies = new StringBlob(pushMissingDependencies);
740        }
741        else {
742            this.pushMissingDependencies.setString(pushMissingDependencies);
743        }
744    }
745
746    public void setPushMissingDependenciesBlob(StringBlob pushMissingDependencies) {
747        this.pushMissingDependencies = pushMissingDependencies;
748    }
749
750    public StringBlob getPushMissingDependenciesBlob() {
751        return pushMissingDependencies;
752    }
753
754    public String getExternalStatus() {
755        return externalStatus;
756    }
757
758    public void setExternalStatus(String externalStatus) {
759        this.externalStatus = externalStatus;
760    }
761
762    @Override
763    public String getTrackerUri() {
764        return trackerUri;
765    }
766
767    public void setTrackerUri(String trackerUri) {
768        this.trackerUri = trackerUri;
769    }
770
771    @Override
772    public String getConsoleUrl() {
773        return consoleUrl;
774    }
775
776    public void setConsoleUrl(String consoleUrl) {
777        this.consoleUrl = consoleUrl;
778    }
779
780    @Override
781    public String getErrorCode() {
782        return errorCode;
783    }
784
785    @Override
786    public String getErrorMessage() {
787        return errorMessage;
788    }
789
790    public void setErrorInfo(String errorCode, String errorMessage) {
791        this.errorCode = errorCode;
792        this.errorMessage = errorMessage;
793    }
794
795    public String getActionXml() {
796        return actionXml == null ? null : actionXml.getString();
797    }
798
799    public void setActionXml(String actionXml) {
800        if (this.actionXml == null) {
801            this.actionXml = new StringBlob(actionXml);
802        }
803        else {
804            this.actionXml.setString(actionXml);
805        }
806    }
807
808    public void setActionXmlBlob(StringBlob actionXml) {
809        this.actionXml = actionXml;
810    }
811
812    public StringBlob getActionXmlBlob() {
813        return actionXml;
814    }
815
816    @Override
817    public String toString() {
818        return MessageFormat.format("CoordinatorAction name[{0}] status[{1}]",
819                                    getId(), getStatus());
820    }
821
822    public int getTimeOut() {
823        return timeOut;
824    }
825
826    public void setTimeOut(int timeOut) {
827        this.timeOut = timeOut;
828    }
829
830
831    public void setErrorCode(String errorCode) {
832        this.errorCode = errorCode;
833    }
834
835    public void setErrorMessage(String errorMessage) {
836        this.errorMessage = errorMessage;
837    }
838
839    @SuppressWarnings("unchecked")
840    public JSONObject toJSONObject(String timeZoneId) {
841        JSONObject json = new JSONObject();
842        json.put(JsonTags.COORDINATOR_ACTION_ID, id);
843        json.put(JsonTags.COORDINATOR_JOB_ID, jobId);
844        json.put(JsonTags.COORDINATOR_ACTION_TYPE, type);
845        json.put(JsonTags.COORDINATOR_ACTION_NUMBER, actionNumber);
846        json.put(JsonTags.COORDINATOR_ACTION_CREATED_CONF, getCreatedConf());
847        json.put(JsonTags.COORDINATOR_ACTION_CREATED_TIME, JsonUtils.formatDateRfc822(getCreatedTime(), timeZoneId));
848        json.put(JsonTags.COORDINATOR_ACTION_NOMINAL_TIME, JsonUtils.formatDateRfc822(getNominalTime(), timeZoneId));
849        json.put(JsonTags.COORDINATOR_ACTION_EXTERNALID, externalId);
850        // json.put(JsonTags.COORDINATOR_ACTION_START_TIME, JsonUtils
851        // .formatDateRfc822(startTime), timeZoneId);
852        json.put(JsonTags.COORDINATOR_ACTION_STATUS, statusStr);
853        json.put(JsonTags.COORDINATOR_ACTION_RUNTIME_CONF, getRunConf());
854        json.put(JsonTags.COORDINATOR_ACTION_LAST_MODIFIED_TIME,
855                JsonUtils.formatDateRfc822(getLastModifiedTime(), timeZoneId));
856        // json.put(JsonTags.COORDINATOR_ACTION_START_TIME, JsonUtils
857        // .formatDateRfc822(startTime), timeZoneId);
858        // json.put(JsonTags.COORDINATOR_ACTION_END_TIME, JsonUtils
859        // .formatDateRfc822(endTime), timeZoneId);
860        json.put(JsonTags.COORDINATOR_ACTION_MISSING_DEPS, getPullInputDependencies().getMissingDependencies());
861        json.put(JsonTags.COORDINATOR_ACTION_PUSH_MISSING_DEPS, getPushInputDependencies().getMissingDependencies());
862        json.put(JsonTags.COORDINATOR_ACTION_EXTERNAL_STATUS, externalStatus);
863        json.put(JsonTags.COORDINATOR_ACTION_TRACKER_URI, trackerUri);
864        json.put(JsonTags.COORDINATOR_ACTION_CONSOLE_URL, consoleUrl);
865        json.put(JsonTags.COORDINATOR_ACTION_ERROR_CODE, errorCode);
866        json.put(JsonTags.COORDINATOR_ACTION_ERROR_MESSAGE, errorMessage);
867        json.put(JsonTags.TO_STRING, toString());
868        return json;
869    }
870
871    /**
872     * Convert a nodes list into a JSONArray.
873     *
874     * @param actions nodes list.
875     * @param timeZoneId time zone to use for dates in the JSON array.
876     * @return the corresponding JSON array.
877     */
878    @SuppressWarnings("unchecked")
879    public static JSONArray toJSONArray(List<CoordinatorActionBean> actions, String timeZoneId) {
880        JSONArray array = new JSONArray();
881        for (CoordinatorActionBean action : actions) {
882            array.add(action.toJSONObject(timeZoneId));
883        }
884        return array;
885    }
886
887    @Override
888    public int hashCode() {
889        final int prime = 31;
890        int result = 1;
891        result = prime * result + ((id == null) ? 0 : id.hashCode());
892        return result;
893    }
894
895    @Override
896    public boolean equals(Object obj) {
897        if (this == obj) {
898            return true;
899        }
900        if (obj == null) {
901            return false;
902        }
903        if (getClass() != obj.getClass()) {
904            return false;
905        }
906        CoordinatorActionBean other = (CoordinatorActionBean) obj;
907        if (id == null) {
908            if (other.id != null) {
909                return false;
910            }
911        }
912        else if (!id.equals(other.id)) {
913            return false;
914        }
915        return true;
916    }
917
918    public CoordInputDependency getPullInputDependencies() {
919        if (coordPullInputDependency == null) {
920            coordPullInputDependency = CoordInputDependencyFactory.getPullInputDependencies(missingDependencies);
921        }
922        return coordPullInputDependency;
923
924    }
925
926    public CoordInputDependency getPushInputDependencies() {
927        if (coordPushInputDependency == null) {
928            coordPushInputDependency = CoordInputDependencyFactory.getPushInputDependencies(pushMissingDependencies);
929        }
930        return coordPushInputDependency;
931    }
932
933    public void setPullInputDependencies(CoordInputDependency coordPullInputDependency) {
934        this.coordPullInputDependency = coordPullInputDependency;
935    }
936
937    public void setPushInputDependencies(CoordInputDependency coordPushInputDependency) {
938        this.coordPushInputDependency = coordPushInputDependency;
939    }
940
941}