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 }