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.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.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", length = 1024) 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, getCred()); 140 WritableUtils.writeStr(dataOutput, getType()); 141 WritableUtils.writeStr(dataOutput, getConf()); 142 WritableUtils.writeStr(dataOutput, getStatusStr()); 143 dataOutput.writeInt(getRetries()); 144 dataOutput.writeLong((getStartTime() != null) ? getStartTime().getTime() : -1); 145 dataOutput.writeLong((getEndTime() != null) ? getEndTime().getTime() : -1); 146 dataOutput.writeLong((getLastCheckTime() != null) ? getLastCheckTime().getTime() : -1); 147 WritableUtils.writeStr(dataOutput, getTransition()); 148 WritableUtils.writeStr(dataOutput, getData()); 149 WritableUtils.writeStr(dataOutput, getExternalId()); 150 WritableUtils.writeStr(dataOutput, getExternalStatus()); 151 WritableUtils.writeStr(dataOutput, getTrackerUri()); 152 WritableUtils.writeStr(dataOutput, getConsoleUrl()); 153 WritableUtils.writeStr(dataOutput, getErrorCode()); 154 WritableUtils.writeStr(dataOutput, getErrorMessage()); 155 WritableUtils.writeStr(dataOutput, wfId); 156 WritableUtils.writeStr(dataOutput, executionPath); 157 dataOutput.writeInt(pending); 158 dataOutput.writeLong((pendingAge != null) ? pendingAge.getTime() : -1); 159 WritableUtils.writeStr(dataOutput, signalValue); 160 WritableUtils.writeStr(dataOutput, logToken); 161 } 162 163 /** 164 * Deserialize an action bean from a data input. 165 * 166 * @param dataInput data input. 167 * @throws IOException thrown if the action bean could not be deserialized. 168 */ 169 public void readFields(DataInput dataInput) throws IOException { 170 setId(WritableUtils.readStr(dataInput)); 171 setName(WritableUtils.readStr(dataInput)); 172 setCred(WritableUtils.readStr(dataInput)); 173 setType(WritableUtils.readStr(dataInput)); 174 setConf(WritableUtils.readStr(dataInput)); 175 setStatus(WorkflowAction.Status.valueOf(WritableUtils.readStr(dataInput))); 176 setRetries(dataInput.readInt()); 177 long d = dataInput.readLong(); 178 if (d != -1) { 179 setStartTime(new Date(d)); 180 } 181 d = dataInput.readLong(); 182 if (d != -1) { 183 setEndTime(new Date(d)); 184 } 185 d = dataInput.readLong(); 186 if (d != -1) { 187 setLastCheckTime(new Date(d)); 188 } 189 setTransition(WritableUtils.readStr(dataInput)); 190 setData(WritableUtils.readStr(dataInput)); 191 setExternalId(WritableUtils.readStr(dataInput)); 192 setExternalStatus(WritableUtils.readStr(dataInput)); 193 setTrackerUri(WritableUtils.readStr(dataInput)); 194 setConsoleUrl(WritableUtils.readStr(dataInput)); 195 setErrorInfo(WritableUtils.readStr(dataInput), WritableUtils.readStr(dataInput)); 196 wfId = WritableUtils.readStr(dataInput); 197 executionPath = WritableUtils.readStr(dataInput); 198 pending = dataInput.readInt(); 199 d = dataInput.readLong(); 200 if (d != -1) { 201 pendingAge = new Date(d); 202 pendingAgeTimestamp = DateUtils.convertDateToTimestamp(pendingAge); 203 } 204 signalValue = WritableUtils.readStr(dataInput); 205 logToken = WritableUtils.readStr(dataInput); 206 } 207 208 /** 209 * Return if the action execution is complete. 210 * 211 * @return if the action start is complete. 212 */ 213 public boolean isExecutionComplete() { 214 return getStatus() == WorkflowAction.Status.DONE; 215 } 216 217 /** 218 * Return if the action is START_RETRY or START_MANUAL or END_RETRY or 219 * END_MANUAL. 220 * 221 * @return boolean true if status is START_RETRY or START_MANUAL or END_RETRY or 222 * END_MANUAL 223 */ 224 public boolean isRetryOrManual() { 225 return (getStatus() == WorkflowAction.Status.START_RETRY || getStatus() == WorkflowAction.Status.START_MANUAL 226 || getStatus() == WorkflowAction.Status.END_RETRY || getStatus() == WorkflowAction.Status.END_MANUAL); 227 } 228 229 /** 230 * Return if the action is complete. 231 * 232 * @return if the action is complete. 233 */ 234 public boolean isComplete() { 235 return getStatus() == WorkflowAction.Status.OK || getStatus() == WorkflowAction.Status.KILLED || 236 getStatus() == WorkflowAction.Status.ERROR; 237 } 238 239 /** 240 * Set the action pending flag to true. 241 */ 242 public void setPendingOnly() { 243 pending = 1; 244 } 245 246 /** 247 * Set the action as pending and the current time as pending. 248 */ 249 public void setPending() { 250 pending = 1; 251 pendingAge = new Date(); 252 pendingAgeTimestamp = DateUtils.convertDateToTimestamp(pendingAge); 253 } 254 255 /** 256 * Set a time when the action will be pending, normally a time in the future. 257 * 258 * @param pendingAge the time when the action will be pending. 259 */ 260 public void setPendingAge(Date pendingAge) { 261 this.pendingAge = pendingAge; 262 this.pendingAgeTimestamp = DateUtils.convertDateToTimestamp(pendingAge); 263 } 264 265 /** 266 * Return the pending age of the action. 267 * 268 * @return the pending age of the action, <code>null</code> if the action is not pending. 269 */ 270 public Date getPendingAge() { 271 return DateUtils.toDate(pendingAgeTimestamp); 272 } 273 274 /** 275 * Return if the action is pending. 276 * 277 * @return if the action is pending. 278 */ 279 public boolean isPending() { 280 return pending == 1 ? true : false; 281 } 282 283 /** 284 * Removes the pending flag and pendingAge from the action. 285 */ 286 public void resetPending() { 287 pending = 0; 288 pendingAge = null; 289 pendingAgeTimestamp = null; 290 } 291 292 /** 293 * Removes the pending flag from the action. 294 */ 295 public void resetPendingOnly() { 296 pending = 0; 297 } 298 299 /** 300 * Increments the number of retries for the action. 301 */ 302 public void incRetries() { 303 setRetries(getRetries() + 1); 304 } 305 306 /** 307 * Set a tracking information for an action, and set the action status to {@link Action.Status#DONE} 308 * 309 * @param externalId external ID for the action. 310 * @param trackerUri tracker URI for the action. 311 * @param consoleUrl console URL for the action. 312 */ 313 public void setStartData(String externalId, String trackerUri, String consoleUrl) { 314 setExternalId(ParamChecker.notEmpty(externalId, "externalId")); 315 setTrackerUri(ParamChecker.notEmpty(trackerUri, "trackerUri")); 316 setConsoleUrl(ParamChecker.notEmpty(consoleUrl, "consoleUrl")); 317 Date now = new Date(); 318 setStartTime(now); 319 setLastCheckTime(now); 320 setStatus(Status.RUNNING); 321 } 322 323 /** 324 * Set the completion information for an action start. Sets the Action status to {@link Action.Status#DONE} 325 * 326 * @param externalStatus action external end status. 327 * @param actionData action output data, <code>null</code> if there is no action output data. 328 */ 329 public void setExecutionData(String externalStatus, Properties actionData) { 330 setStatus(Status.DONE); 331 setExternalStatus(ParamChecker.notEmpty(externalStatus, "externalStatus")); 332 if (actionData != null) { 333 setData(PropertiesUtils.propertiesToString(actionData)); 334 } 335 } 336 337 /** 338 * Set the completion information for an action end. 339 * 340 * @param status action status, {@link Action.Status#OK} or {@link Action.Status#ERROR} or {@link 341 * Action.Status#KILLED} 342 * @param signalValue the signal value. In most cases, the value should be OK or ERROR. 343 */ 344 public void setEndData(Status status, String signalValue) { 345 if (status == null || (status != Status.OK && status != Status.ERROR && status != Status.KILLED)) { 346 throw new IllegalArgumentException("Action status must be OK, ERROR or KILLED. Received [" 347 + status.toString() + "]"); 348 } 349 if (status == Status.OK) { 350 setErrorInfo(null, null); 351 } 352 setStatus(status); 353 setSignalValue(ParamChecker.notEmpty(signalValue, "signalValue")); 354 } 355 356 357 /** 358 * Return the job Id. 359 * 360 * @return the job Id. 361 */ 362 public String getJobId() { 363 return wfId; 364 } 365 366 /** 367 * Return the job Id. 368 * 369 * @return the job Id. 370 */ 371 public String getWfId() { 372 return wfId; 373 } 374 375 /** 376 * Set the job id. 377 * 378 * @param id jobId; 379 */ 380 public void setJobId(String id) { 381 this.wfId = id; 382 } 383 384 public String getSlaXml() { 385 return slaXml; 386 } 387 388 public void setSlaXml(String slaXml) { 389 this.slaXml = slaXml; 390 } 391 392 @Override 393 public void setStatus(Status val) { 394 this.status = val.toString(); 395 super.setStatus(val); 396 } 397 398 public String getStatusStr() { 399 return status; 400 } 401 402 @Override 403 public Status getStatus() { 404 return Status.valueOf(this.status); 405 } 406 407 /** 408 * Return the node execution path. 409 * 410 * @return the node execution path. 411 */ 412 public String getExecutionPath() { 413 return executionPath; 414 } 415 416 /** 417 * Set the node execution path. 418 * 419 * @param executionPath the node execution path. 420 */ 421 public void setExecutionPath(String executionPath) { 422 this.executionPath = executionPath; 423 } 424 425 /** 426 * Return the signal value for the action. <p/> For decision nodes it is the choosen transition, for actions it is 427 * OK or ERROR. 428 * 429 * @return the action signal value. 430 */ 431 public String getSignalValue() { 432 return signalValue; 433 } 434 435 /** 436 * Set the signal value for the action. <p/> For decision nodes it is the choosen transition, for actions it is OK 437 * or ERROR. 438 * 439 * @param signalValue the action signal value. 440 */ 441 public void setSignalValue(String signalValue) { 442 this.signalValue = signalValue; 443 } 444 445 /** 446 * Return the job log token. 447 * 448 * @return the job log token. 449 */ 450 public String getLogToken() { 451 return logToken; 452 } 453 454 /** 455 * Set the job log token. 456 * 457 * @param logToken the job log token. 458 */ 459 public void setLogToken(String logToken) { 460 this.logToken = logToken; 461 } 462 463 /** 464 * Return the action last check time 465 * 466 * @return the last check time 467 */ 468 public Date getLastCheckTime() { 469 return DateUtils.toDate(lastCheckTimestamp); 470 } 471 472 /** 473 * Return the action last check time 474 * 475 * @return the last check time 476 */ 477 public Timestamp getLastCheckTimestamp() { 478 return lastCheckTimestamp; 479 } 480 481 /** 482 * Return the action last check time 483 * 484 * @return the last check time 485 */ 486 public Timestamp getStartTimestamp() { 487 return startTimestamp; 488 } 489 490 /** 491 * Return the action last check time 492 * 493 * @return the last check time 494 */ 495 public Timestamp getEndTimestamp() { 496 return endTimestamp; 497 } 498 499 500 /** 501 * Return the action last check time 502 * 503 * @return the last check time 504 */ 505 public Timestamp getPendingAgeTimestamp() { 506 return pendingAgeTimestamp; 507 } 508 509 /** 510 * Sets the action last check time 511 * 512 * @param lastCheckTime the last check time to set. 513 */ 514 public void setLastCheckTime(Date lastCheckTime) { 515 this.lastCheckTimestamp = DateUtils.convertDateToTimestamp(lastCheckTime); 516 } 517 518 public boolean getPending() { 519 return this.pending == 1 ? true : false; 520 } 521 522 @Override 523 public Date getStartTime() { 524 return DateUtils.toDate(startTimestamp); 525 } 526 527 @Override 528 public void setStartTime(Date startTime) { 529 super.setStartTime(startTime); 530 this.startTimestamp = DateUtils.convertDateToTimestamp(startTime); 531 } 532 533 @Override 534 public Date getEndTime() { 535 return DateUtils.toDate(endTimestamp); 536 } 537 538 @Override 539 public void setEndTime(Date endTime) { 540 super.setEndTime(endTime); 541 this.endTimestamp = DateUtils.convertDateToTimestamp(endTime); 542 } 543 544 }