001 /**
002 * Copyright (c) 2010 Yahoo! Inc. All rights reserved.
003 * Licensed under the Apache License, Version 2.0 (the "License");
004 * you may not use this file except in compliance with the License.
005 * You may obtain a copy of the License at
006 *
007 * http://www.apache.org/licenses/LICENSE-2.0
008 *
009 * Unless required by applicable law or agreed to in writing, software
010 * distributed under the License is distributed on an "AS IS" BASIS,
011 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012 * See the License for the specific language governing permissions and
013 * limitations under the License. See accompanying LICENSE file.
014 */
015 package org.apache.oozie;
016
017 import java.io.DataInput;
018 import java.io.DataOutput;
019 import java.io.IOException;
020 import java.sql.Timestamp;
021 import java.util.Date;
022 import java.util.Properties;
023
024 import javax.persistence.Basic;
025 import javax.persistence.Column;
026 import javax.persistence.Entity;
027 import javax.persistence.Lob;
028 import javax.persistence.NamedQueries;
029 import javax.persistence.NamedQuery;
030 import javax.persistence.Transient;
031
032 import org.apache.hadoop.io.Writable;
033 import org.apache.oozie.client.WorkflowAction;
034 import org.apache.oozie.client.rest.JsonWorkflowAction;
035 import org.apache.oozie.util.DateUtils;
036 import org.apache.oozie.util.ParamChecker;
037 import org.apache.oozie.util.PropertiesUtils;
038 import org.apache.oozie.util.WritableUtils;
039 import org.apache.openjpa.persistence.jdbc.Index;
040
041 /**
042 * Bean that contains all the information to start an action for a workflow node.
043 */
044 @Entity
045 @NamedQueries({
046
047 @NamedQuery(name = "UPDATE_ACTION", query = "update WorkflowActionBean a set a.conf = :conf, a.consoleUrl = :consoleUrl, a.data = :data, a.errorCode = :errorCode, a.errorMessage = :errorMessage, a.externalId = :externalId, a.externalStatus = :externalStatus, a.name = :name, 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.status = :status, a.wfId=:wfId where a.id = :id"),
048
049 @NamedQuery(name = "DELETE_ACTION", query = "delete from WorkflowActionBean a where a.id = :id"),
050
051 @NamedQuery(name = "DELETE_ACTIONS_FOR_WORKFLOW", query = "delete from WorkflowActionBean a where a.wfId = :wfId"),
052
053 @NamedQuery(name = "GET_ACTIONS", query = "select OBJECT(a) from WorkflowActionBean a"),
054
055 @NamedQuery(name = "GET_ACTION", query = "select OBJECT(a) from WorkflowActionBean a where a.id = :id"),
056
057 @NamedQuery(name = "GET_ACTION_FOR_UPDATE", query = "select OBJECT(a) from WorkflowActionBean a where a.id = :id"),
058
059 @NamedQuery(name = "GET_ACTIONS_FOR_WORKFLOW", query = "select OBJECT(a) from WorkflowActionBean a where a.wfId = :wfId order by a.startTimestamp"),
060
061 @NamedQuery(name = "GET_ACTIONS_OF_WORKFLOW_FOR_UPDATE", query = "select OBJECT(a) from WorkflowActionBean a where a.wfId = :wfId order by a.startTimestamp"),
062
063 @NamedQuery(name = "GET_PENDING_ACTIONS", query = "select OBJECT(a) from WorkflowActionBean a where a.pending = 1 AND a.pendingAgeTimestamp < :pendingAge AND a.status <> 'RUNNING'"),
064
065 @NamedQuery(name = "GET_RUNNING_ACTIONS", query = "select OBJECT(a) from WorkflowActionBean a where a.pending = 1 AND a.status = 'RUNNING' AND a.lastCheckTimestamp < :lastCheckTime"),
066
067 @NamedQuery(name = "GET_RETRY_MANUAL_ACTIONS", query = "select OBJECT(a) from WorkflowActionBean a where a.wfId = :wfId AND (a.status = 'START_RETRY' OR a.status = 'START_MANUAL' OR a.status = 'END_RETRY' OR a.status = 'END_MANUAL')") })
068
069 public class WorkflowActionBean extends JsonWorkflowAction implements Writable {
070
071 @Basic
072 @Index
073 @Column(name = "wf_id")
074 private String wfId = null;
075
076 @Basic
077 @Index
078 @Column(name = "status")
079 private String status = WorkflowAction.Status.PREP.toString();
080
081 @Basic
082 @Column(name = "last_check_time")
083 private java.sql.Timestamp lastCheckTimestamp;
084
085 @Basic
086 @Column(name = "end_time")
087 private java.sql.Timestamp endTimestamp = null;
088
089 @Basic
090 @Column(name = "start_time")
091 private java.sql.Timestamp startTimestamp = null;
092
093 @Basic
094 @Column(name = "execution_path")
095 private String executionPath = null;
096
097 @Basic
098 @Column(name = "pending")
099 private int pending = 0;
100
101 // @Temporal(TemporalType.TIME)
102 // @Column(name="pending_age",columnDefinition="timestamp default '0000-00-00 00:00:00'")
103 @Basic
104 @Index
105 @Column(name = "pending_age")
106 private java.sql.Timestamp pendingAgeTimestamp = null;
107
108 @Basic
109 @Column(name = "signal_value")
110 private String signalValue = null;
111
112 @Basic
113 @Column(name = "log_token")
114 private String logToken = null;
115
116 @Transient
117 private Date pendingAge;
118
119 @Column(name = "sla_xml")
120 @Lob
121 private String slaXml = null;
122
123 /**
124 * Default constructor.
125 */
126 public WorkflowActionBean() {
127 }
128
129 /**
130 * Serialize the action bean to a data output.
131 *
132 * @param dataOutput data output.
133 * @throws IOException thrown if the action bean could not be serialized.
134 */
135
136 public void write(DataOutput dataOutput) throws IOException {
137 WritableUtils.writeStr(dataOutput, getId());
138 WritableUtils.writeStr(dataOutput, getName());
139 WritableUtils.writeStr(dataOutput, getType());
140 WritableUtils.writeStr(dataOutput, getConf());
141 WritableUtils.writeStr(dataOutput, getStatusStr());
142 dataOutput.writeInt(getRetries());
143 dataOutput.writeLong((getStartTime() != null) ? getStartTime().getTime() : -1);
144 dataOutput.writeLong((getEndTime() != null) ? getEndTime().getTime() : -1);
145 dataOutput.writeLong((getLastCheckTime() != null) ? getLastCheckTime().getTime() : -1);
146 WritableUtils.writeStr(dataOutput, getTransition());
147 WritableUtils.writeStr(dataOutput, getData());
148 WritableUtils.writeStr(dataOutput, getExternalId());
149 WritableUtils.writeStr(dataOutput, getExternalStatus());
150 WritableUtils.writeStr(dataOutput, getTrackerUri());
151 WritableUtils.writeStr(dataOutput, getConsoleUrl());
152 WritableUtils.writeStr(dataOutput, getErrorCode());
153 WritableUtils.writeStr(dataOutput, getErrorMessage());
154 WritableUtils.writeStr(dataOutput, wfId);
155 WritableUtils.writeStr(dataOutput, executionPath);
156 dataOutput.writeInt(pending);
157 dataOutput.writeLong((pendingAge != null) ? pendingAge.getTime() : -1);
158 WritableUtils.writeStr(dataOutput, signalValue);
159 WritableUtils.writeStr(dataOutput, logToken);
160 }
161
162 /**
163 * Deserialize an action bean from a data input.
164 *
165 * @param dataInput data input.
166 * @throws IOException thrown if the action bean could not be deserialized.
167 */
168 public void readFields(DataInput dataInput) throws IOException {
169 setId(WritableUtils.readStr(dataInput));
170 setName(WritableUtils.readStr(dataInput));
171 setType(WritableUtils.readStr(dataInput));
172 setConf(WritableUtils.readStr(dataInput));
173 setStatus(WorkflowAction.Status.valueOf(WritableUtils.readStr(dataInput)));
174 setRetries(dataInput.readInt());
175 long d = dataInput.readLong();
176 if (d != -1) {
177 setStartTime(new Date(d));
178 }
179 d = dataInput.readLong();
180 if (d != -1) {
181 setEndTime(new Date(d));
182 }
183 d = dataInput.readLong();
184 if (d != -1) {
185 setLastCheckTime(new Date(d));
186 }
187 setTransition(WritableUtils.readStr(dataInput));
188 setData(WritableUtils.readStr(dataInput));
189 setExternalId(WritableUtils.readStr(dataInput));
190 setExternalStatus(WritableUtils.readStr(dataInput));
191 setTrackerUri(WritableUtils.readStr(dataInput));
192 setConsoleUrl(WritableUtils.readStr(dataInput));
193 setErrorInfo(WritableUtils.readStr(dataInput), WritableUtils.readStr(dataInput));
194 wfId = WritableUtils.readStr(dataInput);
195 executionPath = WritableUtils.readStr(dataInput);
196 pending = dataInput.readInt();
197 d = dataInput.readLong();
198 if (d != -1) {
199 pendingAge = new Date(d);
200 pendingAgeTimestamp = DateUtils.convertDateToTimestamp(pendingAge);
201 }
202 signalValue = WritableUtils.readStr(dataInput);
203 logToken = WritableUtils.readStr(dataInput);
204 }
205
206 /**
207 * Return if the action execution is complete.
208 *
209 * @return if the action start is complete.
210 */
211 public boolean isExecutionComplete() {
212 return getStatus() == WorkflowAction.Status.DONE;
213 }
214
215 /**
216 * Return if the action is START_RETRY or START_MANUAL or END_RETRY or
217 * END_MANUAL.
218 *
219 * @return boolean true if status is START_RETRY or START_MANUAL or END_RETRY or
220 * END_MANUAL
221 */
222 public boolean isRetryOrManual() {
223 return (getStatus() == WorkflowAction.Status.START_RETRY || getStatus() == WorkflowAction.Status.START_MANUAL
224 || getStatus() == WorkflowAction.Status.END_RETRY || getStatus() == WorkflowAction.Status.END_MANUAL);
225 }
226
227 /**
228 * Return if the action is complete.
229 *
230 * @return if the action is complete.
231 */
232 public boolean isComplete() {
233 return getStatus() == WorkflowAction.Status.OK || getStatus() == WorkflowAction.Status.KILLED ||
234 getStatus() == WorkflowAction.Status.ERROR;
235 }
236
237 /**
238 * Set the action pending flag to true.
239 */
240 public void setPendingOnly() {
241 pending = 1;
242 }
243
244 /**
245 * Set the action as pending and the current time as pending.
246 */
247 public void setPending() {
248 pending = 1;
249 pendingAge = new Date();
250 pendingAgeTimestamp = DateUtils.convertDateToTimestamp(pendingAge);
251 }
252
253 /**
254 * Set a time when the action will be pending, normally a time in the future.
255 *
256 * @param pendingAge the time when the action will be pending.
257 */
258 public void setPendingAge(Date pendingAge) {
259 this.pendingAge = pendingAge;
260 this.pendingAgeTimestamp = DateUtils.convertDateToTimestamp(pendingAge);
261 }
262
263 /**
264 * Return the pending age of the action.
265 *
266 * @return the pending age of the action, <code>null</code> if the action is not pending.
267 */
268 public Date getPendingAge() {
269 return DateUtils.toDate(pendingAgeTimestamp);
270 }
271
272 /**
273 * Return if the action is pending.
274 *
275 * @return if the action is pending.
276 */
277 public boolean isPending() {
278 return pending == 1 ? true : false;
279 }
280
281 /**
282 * Removes the pending flag and pendingAge from the action.
283 */
284 public void resetPending() {
285 pending = 0;
286 pendingAge = null;
287 pendingAgeTimestamp = null;
288 }
289
290 /**
291 * Removes the pending flag from the action.
292 */
293 public void resetPendingOnly() {
294 pending = 0;
295 }
296
297 /**
298 * Increments the number of retries for the action.
299 */
300 public void incRetries() {
301 setRetries(getRetries() + 1);
302 }
303
304 /**
305 * Set a tracking information for an action, and set the action status to {@link Action.Status#DONE}
306 *
307 * @param externalId external ID for the action.
308 * @param trackerUri tracker URI for the action.
309 * @param consoleUrl console URL for the action.
310 */
311 public void setStartData(String externalId, String trackerUri, String consoleUrl) {
312 setExternalId(ParamChecker.notEmpty(externalId, "externalId"));
313 setTrackerUri(ParamChecker.notEmpty(trackerUri, "trackerUri"));
314 setConsoleUrl(ParamChecker.notEmpty(consoleUrl, "consoleUrl"));
315 Date now = new Date();
316 setStartTime(now);
317 setLastCheckTime(now);
318 setStatus(Status.RUNNING);
319 }
320
321 /**
322 * Set the completion information for an action start. Sets the Action status to {@link Action.Status#DONE}
323 *
324 * @param externalStatus action external end status.
325 * @param actionData action output data, <code>null</code> if there is no action output data.
326 */
327 public void setExecutionData(String externalStatus, Properties actionData) {
328 setStatus(Status.DONE);
329 setExternalStatus(ParamChecker.notEmpty(externalStatus, "externalStatus"));
330 if (actionData != null) {
331 setData(PropertiesUtils.propertiesToString(actionData));
332 }
333 }
334
335 /**
336 * Set the completion information for an action end.
337 *
338 * @param status action status, {@link Action.Status#OK} or {@link Action.Status#ERROR} or {@link
339 * Action.Status#KILLED}
340 * @param signalValue the signal value. In most cases, the value should be OK or ERROR.
341 */
342 public void setEndData(Status status, String signalValue) {
343 if (status == null || (status != Status.OK && status != Status.ERROR && status != Status.KILLED)) {
344 throw new IllegalArgumentException("Action status must be OK, ERROR or KILLED. Received ["
345 + status.toString() + "]");
346 }
347 if (status == Status.OK) {
348 setErrorInfo(null, null);
349 }
350 setStatus(status);
351 setSignalValue(ParamChecker.notEmpty(signalValue, "signalValue"));
352 }
353
354
355 /**
356 * Return the job Id.
357 *
358 * @return the job Id.
359 */
360 public String getJobId() {
361 return wfId;
362 }
363
364 /**
365 * Return the job Id.
366 *
367 * @return the job Id.
368 */
369 public String getWfId() {
370 return wfId;
371 }
372
373 /**
374 * Set the job id.
375 *
376 * @param id jobId;
377 */
378 public void setJobId(String id) {
379 this.wfId = id;
380 }
381
382 public String getSlaXml() {
383 return slaXml;
384 }
385
386 public void setSlaXml(String slaXml) {
387 this.slaXml = slaXml;
388 }
389
390 @Override
391 public void setStatus(Status val) {
392 this.status = val.toString();
393 super.setStatus(val);
394 }
395
396 public String getStatusStr() {
397 return status;
398 }
399
400 @Override
401 public Status getStatus() {
402 return Status.valueOf(this.status);
403 }
404
405 /**
406 * Return the node execution path.
407 *
408 * @return the node execution path.
409 */
410 public String getExecutionPath() {
411 return executionPath;
412 }
413
414 /**
415 * Set the node execution path.
416 *
417 * @param executionPath the node execution path.
418 */
419 public void setExecutionPath(String executionPath) {
420 this.executionPath = executionPath;
421 }
422
423 /**
424 * Return the signal value for the action. <p/> For decision nodes it is the choosen transition, for actions it is
425 * OK or ERROR.
426 *
427 * @return the action signal value.
428 */
429 public String getSignalValue() {
430 return signalValue;
431 }
432
433 /**
434 * Set the signal value for the action. <p/> For decision nodes it is the choosen transition, for actions it is OK
435 * or ERROR.
436 *
437 * @param signalValue the action signal value.
438 */
439 public void setSignalValue(String signalValue) {
440 this.signalValue = signalValue;
441 }
442
443 /**
444 * Return the job log token.
445 *
446 * @return the job log token.
447 */
448 public String getLogToken() {
449 return logToken;
450 }
451
452 /**
453 * Set the job log token.
454 *
455 * @param logToken the job log token.
456 */
457 public void setLogToken(String logToken) {
458 this.logToken = logToken;
459 }
460
461 /**
462 * Return the action last check time
463 *
464 * @return the last check time
465 */
466 public Date getLastCheckTime() {
467 return DateUtils.toDate(lastCheckTimestamp);
468 }
469
470 /**
471 * Return the action last check time
472 *
473 * @return the last check time
474 */
475 public Timestamp getLastCheckTimestamp() {
476 return lastCheckTimestamp;
477 }
478
479 /**
480 * Return the action last check time
481 *
482 * @return the last check time
483 */
484 public Timestamp getStartTimestamp() {
485 return startTimestamp;
486 }
487
488 /**
489 * Return the action last check time
490 *
491 * @return the last check time
492 */
493 public Timestamp getEndTimestamp() {
494 return endTimestamp;
495 }
496
497
498 /**
499 * Return the action last check time
500 *
501 * @return the last check time
502 */
503 public Timestamp getPendingAgeTimestamp() {
504 return pendingAgeTimestamp;
505 }
506
507 /**
508 * Sets the action last check time
509 *
510 * @param lastCheckTime the last check time to set.
511 */
512 public void setLastCheckTime(Date lastCheckTime) {
513 this.lastCheckTimestamp = DateUtils.convertDateToTimestamp(lastCheckTime);
514 }
515
516 public boolean getPending() {
517 return this.pending == 1 ? true : false;
518 }
519
520 @Override
521 public Date getStartTime() {
522 return DateUtils.toDate(startTimestamp);
523 }
524
525 @Override
526 public void setStartTime(Date startTime) {
527 super.setStartTime(startTime);
528 this.startTimestamp = DateUtils.convertDateToTimestamp(startTime);
529 }
530
531 @Override
532 public Date getEndTime() {
533 return DateUtils.toDate(endTimestamp);
534 }
535
536 @Override
537 public void setEndTime(Date endTime) {
538 super.setEndTime(endTime);
539 this.endTimestamp = DateUtils.convertDateToTimestamp(endTime);
540 }
541
542 }