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.store; 020 021import java.sql.Connection; 022import java.sql.SQLException; 023import java.sql.Timestamp; 024import java.util.ArrayList; 025import java.util.List; 026import java.util.Map; 027import java.util.concurrent.Callable; 028 029import javax.persistence.EntityManager; 030import javax.persistence.Query; 031 032import org.apache.oozie.ErrorCode; 033import org.apache.oozie.WorkflowActionBean; 034import org.apache.oozie.WorkflowJobBean; 035import org.apache.oozie.WorkflowsInfo; 036import org.apache.oozie.client.OozieClient; 037import org.apache.oozie.client.WorkflowJob.Status; 038import org.apache.oozie.executor.jpa.JPAExecutorException; 039import org.apache.oozie.executor.jpa.WorkflowActionQueryExecutor; 040import org.apache.oozie.executor.jpa.WorkflowJobQueryExecutor; 041import org.apache.oozie.service.InstrumentationService; 042import org.apache.oozie.service.SchemaService; 043import org.apache.oozie.service.Services; 044import org.apache.oozie.service.SchemaService.SchemaName; 045import org.apache.oozie.util.Instrumentation; 046import org.apache.oozie.util.ParamChecker; 047import org.apache.oozie.util.XLog; 048import org.apache.oozie.workflow.WorkflowException; 049import org.apache.openjpa.persistence.OpenJPAEntityManager; 050import org.apache.openjpa.persistence.OpenJPAPersistence; 051import org.apache.openjpa.persistence.OpenJPAQuery; 052import org.apache.openjpa.persistence.jdbc.FetchDirection; 053import org.apache.openjpa.persistence.jdbc.JDBCFetchPlan; 054import org.apache.openjpa.persistence.jdbc.LRSSizeAlgorithm; 055import org.apache.openjpa.persistence.jdbc.ResultSetType; 056 057/** 058 * DB Implementation of Workflow Store 059 */ 060public class WorkflowStore extends Store { 061 private Connection conn; 062 private EntityManager entityManager; 063 private boolean selectForUpdate; 064 private static final String INSTR_GROUP = "db"; 065 public static final int LOCK_TIMEOUT = 50000; 066 private static final String seletStr = "Select w.id, w.appName, w.statusStr, w.run, w.user, w.group, w.createdTimestamp, " 067 + "w.startTimestamp, w.lastModifiedTimestamp, w.endTimestamp from WorkflowJobBean w"; 068 private static final String countStr = "Select count(w) from WorkflowJobBean w"; 069 070 public WorkflowStore() { 071 } 072 073 public WorkflowStore(Connection connection, boolean selectForUpdate) throws StoreException { 074 super(); 075 conn = ParamChecker.notNull(connection, "conn"); 076 entityManager = getEntityManager(); 077 this.selectForUpdate = selectForUpdate; 078 } 079 080 public WorkflowStore(Connection connection, Store store, boolean selectForUpdate) throws StoreException { 081 super(store); 082 conn = ParamChecker.notNull(connection, "conn"); 083 entityManager = getEntityManager(); 084 this.selectForUpdate = selectForUpdate; 085 } 086 087 public WorkflowStore(boolean selectForUpdate) throws StoreException { 088 super(); 089 entityManager = getEntityManager(); 090 javax.xml.validation.Schema schema = Services.get().get(SchemaService.class).getSchema(SchemaName.WORKFLOW); 091 OpenJPAEntityManager kem = OpenJPAPersistence.cast(entityManager); 092 conn = (Connection) kem.getConnection(); 093 this.selectForUpdate = selectForUpdate; 094 } 095 096 public WorkflowStore(Store store, boolean selectForUpdate) throws StoreException { 097 super(store); 098 entityManager = getEntityManager(); 099 this.selectForUpdate = selectForUpdate; 100 } 101 102 /** 103 * Create a Workflow and return a WorkflowJobBean. It also creates the process instance for the job. 104 * 105 * @param workflow workflow bean 106 * @throws StoreException 107 */ 108 109 public void insertWorkflow(final WorkflowJobBean workflow) throws StoreException { 110 ParamChecker.notNull(workflow, "workflow"); 111 112 doOperation("insertWorkflow", new Callable<Void>() { 113 public Void call() throws SQLException, StoreException, WorkflowException { 114 entityManager.persist(workflow); 115 return null; 116 } 117 }); 118 } 119 120 /** 121 * Load the Workflow into a Bean and return it. Also load the Workflow Instance into the bean. And lock the Workflow 122 * depending on the locking parameter. 123 * 124 * @param id Workflow ID 125 * @param locking true if Workflow is to be locked 126 * @return WorkflowJobBean 127 * @throws StoreException 128 */ 129 public WorkflowJobBean getWorkflow(final String id, final boolean locking) throws StoreException { 130 ParamChecker.notEmpty(id, "WorkflowID"); 131 WorkflowJobBean wfBean = doOperation("getWorkflow", new Callable<WorkflowJobBean>() { 132 public WorkflowJobBean call() throws SQLException, StoreException, WorkflowException, InterruptedException { 133 WorkflowJobBean wfBean = null; 134 wfBean = getWorkflowOnly(id, locking); 135 if (wfBean == null) { 136 throw new StoreException(ErrorCode.E0604, id); 137 } 138 /* 139 * WorkflowInstance wfInstance; //krishna and next line 140 * wfInstance = workflowLib.get(id); wfInstance = 141 * wfBean.get(wfBean.getWfInstance()); 142 * wfBean.setWorkflowInstance(wfInstance); 143 * wfBean.setWfInstance(wfInstance); 144 */ 145 return wfBean; 146 } 147 }); 148 return wfBean; 149 } 150 151 /** 152 * Get the number of Workflows with the given status. 153 * 154 * @param status Workflow Status. 155 * @return number of Workflows with given status. 156 * @throws StoreException 157 */ 158 public int getWorkflowCountWithStatus(final String status) throws StoreException { 159 ParamChecker.notEmpty(status, "status"); 160 Integer cnt = doOperation("getWorkflowCountWithStatus", new Callable<Integer>() { 161 public Integer call() throws SQLException { 162 Query q = entityManager.createNamedQuery("GET_WORKFLOWS_COUNT_WITH_STATUS"); 163 q.setParameter("status", status); 164 Long count = (Long) q.getSingleResult(); 165 return Integer.valueOf(count.intValue()); 166 } 167 }); 168 return cnt.intValue(); 169 } 170 171 /** 172 * Get the number of Workflows with the given status which was modified in given time limit. 173 * 174 * @param status Workflow Status. 175 * @param secs No. of seconds within which the workflow got modified. 176 * @return number of Workflows modified within given time with given status. 177 * @throws StoreException 178 */ 179 public int getWorkflowCountWithStatusInLastNSeconds(final String status, final int secs) throws StoreException { 180 ParamChecker.notEmpty(status, "status"); 181 ParamChecker.notEmpty(status, "secs"); 182 Integer cnt = doOperation("getWorkflowCountWithStatusInLastNSecs", new Callable<Integer>() { 183 public Integer call() throws SQLException { 184 Query q = entityManager.createNamedQuery("GET_WORKFLOWS_COUNT_WITH_STATUS_IN_LAST_N_SECS"); 185 Timestamp ts = new Timestamp(System.currentTimeMillis() - (secs * 1000)); 186 q.setParameter("status", status); 187 q.setParameter("lastModTime", ts); 188 Long count = (Long) q.getSingleResult(); 189 return Integer.valueOf(count.intValue()); 190 } 191 }); 192 return cnt.intValue(); 193 } 194 195 /** 196 * Update the data from Workflow Bean to DB along with the workflow instance data. Action table is not updated 197 * 198 * @param wfBean Workflow Bean 199 * @throws StoreException If Workflow doesn't exist 200 */ 201 public void updateWorkflow(final WorkflowJobBean wfBean) throws StoreException { 202 ParamChecker.notNull(wfBean, "WorkflowJobBean"); 203 doOperation("updateWorkflow", new Callable<Void>() { 204 public Void call() throws SQLException, StoreException, WorkflowException, JPAExecutorException { 205 WorkflowJobQueryExecutor.getInstance().executeUpdate( 206 WorkflowJobQueryExecutor.WorkflowJobQuery.UPDATE_WORKFLOW, wfBean); 207 return null; 208 } 209 }); 210 } 211 212 /** 213 * Create a new Action record in the ACTIONS table with the given Bean. 214 * 215 * @param action WorkflowActionBean 216 * @throws StoreException If the action is already present 217 */ 218 public void insertAction(final WorkflowActionBean action) throws StoreException { 219 ParamChecker.notNull(action, "WorkflowActionBean"); 220 doOperation("insertAction", new Callable<Void>() { 221 public Void call() throws SQLException, StoreException, WorkflowException { 222 entityManager.persist(action); 223 return null; 224 } 225 }); 226 } 227 228 /** 229 * Load the action data and returns a bean. 230 * 231 * @param id Action Id 232 * @param locking true if the action is to be locked 233 * @return Action Bean 234 * @throws StoreException If action doesn't exist 235 */ 236 public WorkflowActionBean getAction(final String id, final boolean locking) throws StoreException { 237 ParamChecker.notEmpty(id, "ActionID"); 238 WorkflowActionBean action = doOperation("getAction", new Callable<WorkflowActionBean>() { 239 public WorkflowActionBean call() throws SQLException, StoreException, WorkflowException, 240 InterruptedException { 241 Query q = entityManager.createNamedQuery("GET_ACTION"); 242 /* 243 * if (locking) { OpenJPAQuery oq = OpenJPAPersistence.cast(q); 244 * FetchPlan fetch = oq.getFetchPlan(); 245 * fetch.setReadLockMode(LockModeType.WRITE); 246 * fetch.setLockTimeout(1000); // 1 seconds } 247 */ 248 WorkflowActionBean action = null; 249 q.setParameter("id", id); 250 List<WorkflowActionBean> actions = q.getResultList(); 251 // action = (WorkflowActionBean) q.getSingleResult(); 252 if (actions.size() > 0) { 253 action = actions.get(0); 254 } 255 else { 256 throw new StoreException(ErrorCode.E0605, id); 257 } 258 259 /* 260 * if (locking) return action; else 261 */ 262 // return action; 263 return getBeanForRunningAction(action); 264 } 265 }); 266 return action; 267 } 268 269 /** 270 * Update the given action bean to DB. 271 * 272 * @param action Action Bean 273 * @throws StoreException if action doesn't exist 274 */ 275 public void updateAction(final WorkflowActionBean action) throws StoreException { 276 ParamChecker.notNull(action, "WorkflowActionBean"); 277 doOperation("updateAction", new Callable<Void>() { 278 public Void call() throws SQLException, StoreException, WorkflowException, JPAExecutorException { 279 WorkflowActionQueryExecutor.getInstance().executeUpdate( 280 WorkflowActionQueryExecutor.WorkflowActionQuery.UPDATE_ACTION, action); 281 return null; 282 } 283 }); 284 } 285 286 /** 287 * Delete the Action with given id. 288 * 289 * @param id Action ID 290 * @throws StoreException if Action doesn't exist 291 */ 292 public void deleteAction(final String id) throws StoreException { 293 ParamChecker.notEmpty(id, "ActionID"); 294 doOperation("deleteAction", new Callable<Void>() { 295 public Void call() throws SQLException, StoreException, WorkflowException { 296 /* 297 * Query q = entityManager.createNamedQuery("DELETE_ACTION"); 298 * q.setParameter("id", id); q.executeUpdate(); 299 */ 300 WorkflowActionBean action = entityManager.find(WorkflowActionBean.class, id); 301 if (action != null) { 302 entityManager.remove(action); 303 } 304 return null; 305 } 306 }); 307 } 308 309 /** 310 * Loads all the actions for the given Workflow. Also locks all the actions if locking is true. 311 * 312 * @param wfId Workflow ID 313 * @param locking true if Actions are to be locked 314 * @return A List of WorkflowActionBean 315 * @throws StoreException 316 */ 317 public List<WorkflowActionBean> getActionsForWorkflow(final String wfId, final boolean locking) 318 throws StoreException { 319 ParamChecker.notEmpty(wfId, "WorkflowID"); 320 List<WorkflowActionBean> actions = doOperation("getActionsForWorkflow", 321 new Callable<List<WorkflowActionBean>>() { 322 public List<WorkflowActionBean> call() throws SQLException, 323 StoreException, WorkflowException, 324 InterruptedException { 325 List<WorkflowActionBean> actions; 326 List<WorkflowActionBean> actionList 327 = new ArrayList<WorkflowActionBean>(); 328 try { 329 Query q = entityManager.createNamedQuery( 330 "GET_ACTIONS_FOR_WORKFLOW"); 331 332 /* 333 * OpenJPAQuery oq = OpenJPAPersistence.cast(q); 334 * if (locking) { // 335 * q.setHint("openjpa.FetchPlan.ReadLockMode" 336 * ,"WRITE"); FetchPlan fetch = oq.getFetchPlan(); 337 * fetch.setReadLockMode(LockModeType.WRITE); 338 * fetch.setLockTimeout(1000); // 1 seconds } 339 */ 340 q.setParameter("wfId", wfId); 341 actions = q.getResultList(); 342 for (WorkflowActionBean a : actions) { 343 WorkflowActionBean aa = getBeanForRunningAction(a); 344 actionList.add(aa); 345 } 346 } 347 catch (IllegalStateException e) { 348 throw new StoreException(ErrorCode.E0601, e.getMessage(), e); 349 } 350 /* 351 * if (locking) { return actions; } else { 352 */ 353 return actionList; 354 // } 355 } 356 }); 357 return actions; 358 } 359 360 /** 361 * Loads given number of actions for the given Workflow. Also locks all the actions if locking is true. 362 * 363 * @param wfId Workflow ID 364 * @param start offset for select statement 365 * @param len number of Workflow Actions to be returned 366 * @return A List of WorkflowActionBean 367 * @throws StoreException 368 */ 369 public List<WorkflowActionBean> getActionsSubsetForWorkflow(final String wfId, final int start, final int len) 370 throws StoreException { 371 ParamChecker.notEmpty(wfId, "WorkflowID"); 372 List<WorkflowActionBean> actions = doOperation("getActionsForWorkflow", 373 new Callable<List<WorkflowActionBean>>() { 374 public List<WorkflowActionBean> call() throws SQLException, 375 StoreException, WorkflowException, 376 InterruptedException { 377 List<WorkflowActionBean> actions; 378 List<WorkflowActionBean> actionList 379 = new ArrayList<WorkflowActionBean>(); 380 try { 381 Query q = entityManager.createNamedQuery( 382 "GET_ACTIONS_FOR_WORKFLOW"); 383 OpenJPAQuery oq = OpenJPAPersistence.cast(q); 384 q.setParameter("wfId", wfId); 385 q.setFirstResult(start - 1); 386 q.setMaxResults(len); 387 actions = q.getResultList(); 388 for (WorkflowActionBean a : actions) { 389 WorkflowActionBean aa = getBeanForRunningAction(a); 390 actionList.add(aa); 391 } 392 } 393 catch (IllegalStateException e) { 394 throw new StoreException(ErrorCode.E0601, e.getMessage(), e); 395 } 396 return actionList; 397 } 398 }); 399 return actions; 400 } 401 402 /** 403 * Load All the actions that are pending for more than given time. 404 * 405 * @param minimumPendingAgeSecs Minimum Pending age in seconds 406 * @return List of action beans 407 * @throws StoreException 408 */ 409 public List<WorkflowActionBean> getPendingActions(final long minimumPendingAgeSecs) throws StoreException { 410 List<WorkflowActionBean> actions = doOperation("getPendingActions", new Callable<List<WorkflowActionBean>>() { 411 public List<WorkflowActionBean> call() throws SQLException, StoreException, WorkflowException { 412 Timestamp ts = new Timestamp(System.currentTimeMillis() - minimumPendingAgeSecs * 1000); 413 List<WorkflowActionBean> actionList = null; 414 try { 415 Query q = entityManager.createNamedQuery("GET_PENDING_ACTIONS"); 416 q.setParameter("pendingAge", ts); 417 actionList = q.getResultList(); 418 } 419 catch (IllegalStateException e) { 420 throw new StoreException(ErrorCode.E0601, e.getMessage(), e); 421 } 422 return actionList; 423 } 424 }); 425 return actions; 426 } 427 428 /** 429 * Load All the actions that are running and were last checked after now - miminumCheckAgeSecs 430 * 431 * @param checkAgeSecs check age in seconds. 432 * @return List of action beans. 433 * @throws StoreException 434 */ 435 public List<WorkflowActionBean> getRunningActions(final long checkAgeSecs) throws StoreException { 436 List<WorkflowActionBean> actions = doOperation("getRunningActions", new Callable<List<WorkflowActionBean>>() { 437 438 public List<WorkflowActionBean> call() throws SQLException, StoreException, WorkflowException { 439 List<WorkflowActionBean> actions = new ArrayList<WorkflowActionBean>(); 440 Timestamp ts = new Timestamp(System.currentTimeMillis() - checkAgeSecs * 1000); 441 try { 442 Query q = entityManager.createNamedQuery("GET_RUNNING_ACTIONS"); 443 q.setParameter("lastCheckTime", ts); 444 actions = q.getResultList(); 445 } 446 catch (IllegalStateException e) { 447 throw new StoreException(ErrorCode.E0601, e.getMessage(), e); 448 } 449 450 return actions; 451 } 452 }); 453 return actions; 454 } 455 456 /** 457 * Load All the actions that are START_RETRY or START_MANUAL or END_RETRY or END_MANUAL. 458 * 459 * @param wfId String 460 * @return List of action beans 461 * @throws StoreException 462 */ 463 public List<WorkflowActionBean> getRetryAndManualActions(final String wfId) throws StoreException { 464 List<WorkflowActionBean> actions = doOperation("GET_RETRY_MANUAL_ACTIONS", 465 new Callable<List<WorkflowActionBean>>() { 466 public List<WorkflowActionBean> call() throws SQLException, StoreException, WorkflowException { 467 List<WorkflowActionBean> actionList = null; 468 try { 469 Query q = entityManager.createNamedQuery("GET_RETRY_MANUAL_ACTIONS"); 470 q.setParameter("wfId", wfId); 471 actionList = q.getResultList(); 472 } 473 catch (IllegalStateException e) { 474 throw new StoreException(ErrorCode.E0601, e.getMessage(), e); 475 } 476 477 return actionList; 478 } 479 }); 480 return actions; 481 } 482 483 /** 484 * Loads all the jobs that are satisfying the given filter condition. Filters can be applied on user, group, 485 * appName, status. 486 * 487 * @param filter Filter condition 488 * @param start offset for select statement 489 * @param len number of Workflows to be returned 490 * @return A list of workflows 491 * @throws StoreException 492 */ 493 public WorkflowsInfo getWorkflowsInfo(final Map<String, List<String>> filter, final int start, final int len) 494 throws StoreException { 495 496 WorkflowsInfo workFlowsInfo = doOperation("getWorkflowsInfo", new Callable<WorkflowsInfo>() { 497 @SuppressWarnings("unchecked") 498 public WorkflowsInfo call() throws SQLException, StoreException { 499 500 List<String> orArray = new ArrayList<String>(); 501 List<String> colArray = new ArrayList<String>(); 502 List<String> valArray = new ArrayList<String>(); 503 StringBuilder sb = new StringBuilder(""); 504 boolean isStatus = false; 505 boolean isGroup = false; 506 boolean isAppName = false; 507 boolean isUser = false; 508 boolean isEnabled = false; 509 int index = 0; 510 for (Map.Entry<String, List<String>> entry : filter.entrySet()) { 511 String colName = null; 512 String colVar = null; 513 if (entry.getKey().equals(OozieClient.FILTER_GROUP)) { 514 List<String> values = filter.get(OozieClient.FILTER_GROUP); 515 colName = "group"; 516 for (int i = 0; i < values.size(); i++) { 517 colVar = "group"; 518 colVar = colVar + index; 519 if (!isEnabled && !isGroup) { 520 sb.append(seletStr).append(" where w.group IN (:group" + index); 521 isGroup = true; 522 isEnabled = true; 523 } 524 else { 525 if (isEnabled && !isGroup) { 526 sb.append(" and w.group IN (:group" + index); 527 isGroup = true; 528 } 529 else { 530 if (isGroup) { 531 sb.append(", :group" + index); 532 } 533 } 534 } 535 if (i == values.size() - 1) { 536 sb.append(")"); 537 } 538 index++; 539 valArray.add(values.get(i)); 540 orArray.add(colName); 541 colArray.add(colVar); 542 } 543 } 544 else { 545 if (entry.getKey().equals(OozieClient.FILTER_STATUS)) { 546 List<String> values = filter.get(OozieClient.FILTER_STATUS); 547 colName = "status"; 548 for (int i = 0; i < values.size(); i++) { 549 colVar = "status"; 550 colVar = colVar + index; 551 if (!isEnabled && !isStatus) { 552 sb.append(seletStr).append(" where w.statusStr IN (:status" + index); 553 isStatus = true; 554 isEnabled = true; 555 } 556 else { 557 if (isEnabled && !isStatus) { 558 sb.append(" and w.statusStr IN (:status" + index); 559 isStatus = true; 560 } 561 else { 562 if (isStatus) { 563 sb.append(", :status" + index); 564 } 565 } 566 } 567 if (i == values.size() - 1) { 568 sb.append(")"); 569 } 570 index++; 571 valArray.add(values.get(i)); 572 orArray.add(colName); 573 colArray.add(colVar); 574 } 575 } 576 else { 577 if (entry.getKey().equals(OozieClient.FILTER_NAME)) { 578 List<String> values = filter.get(OozieClient.FILTER_NAME); 579 colName = "appName"; 580 for (int i = 0; i < values.size(); i++) { 581 colVar = "appName"; 582 colVar = colVar + index; 583 if (!isEnabled && !isAppName) { 584 sb.append(seletStr).append(" where w.appName IN (:appName" + index); 585 isAppName = true; 586 isEnabled = true; 587 } 588 else { 589 if (isEnabled && !isAppName) { 590 sb.append(" and w.appName IN (:appName" + index); 591 isAppName = true; 592 } 593 else { 594 if (isAppName) { 595 sb.append(", :appName" + index); 596 } 597 } 598 } 599 if (i == values.size() - 1) { 600 sb.append(")"); 601 } 602 index++; 603 valArray.add(values.get(i)); 604 orArray.add(colName); 605 colArray.add(colVar); 606 } 607 } 608 else { 609 if (entry.getKey().equals(OozieClient.FILTER_USER)) { 610 List<String> values = filter.get(OozieClient.FILTER_USER); 611 colName = "user"; 612 for (int i = 0; i < values.size(); i++) { 613 colVar = "user"; 614 colVar = colVar + index; 615 if (!isEnabled && !isUser) { 616 sb.append(seletStr).append(" where w.user IN (:user" + index); 617 isUser = true; 618 isEnabled = true; 619 } 620 else { 621 if (isEnabled && !isUser) { 622 sb.append(" and w.user IN (:user" + index); 623 isUser = true; 624 } 625 else { 626 if (isUser) { 627 sb.append(", :user" + index); 628 } 629 } 630 } 631 if (i == values.size() - 1) { 632 sb.append(")"); 633 } 634 index++; 635 valArray.add(values.get(i)); 636 orArray.add(colName); 637 colArray.add(colVar); 638 } 639 } 640 } 641 } 642 } 643 } 644 645 int realLen = 0; 646 647 Query q = null; 648 Query qTotal = null; 649 if (orArray.size() == 0) { 650 q = entityManager.createNamedQuery("GET_WORKFLOWS_COLUMNS"); 651 q.setFirstResult(start - 1); 652 q.setMaxResults(len); 653 qTotal = entityManager.createNamedQuery("GET_WORKFLOWS_COUNT"); 654 } 655 else { 656 if (orArray.size() > 0) { 657 StringBuilder sbTotal = new StringBuilder(sb); 658 sb.append(" order by w.startTimestamp desc "); 659 XLog.getLog(getClass()).debug("Created String is **** " + sb.toString()); 660 q = entityManager.createQuery(sb.toString()); 661 q.setFirstResult(start - 1); 662 q.setMaxResults(len); 663 qTotal = entityManager.createQuery(sbTotal.toString().replace(seletStr, countStr)); 664 for (int i = 0; i < orArray.size(); i++) { 665 q.setParameter(colArray.get(i), valArray.get(i)); 666 qTotal.setParameter(colArray.get(i), valArray.get(i)); 667 } 668 } 669 } 670 671 OpenJPAQuery kq = OpenJPAPersistence.cast(q); 672 JDBCFetchPlan fetch = (JDBCFetchPlan) kq.getFetchPlan(); 673 fetch.setFetchBatchSize(20); 674 fetch.setResultSetType(ResultSetType.SCROLL_INSENSITIVE); 675 fetch.setFetchDirection(FetchDirection.FORWARD); 676 fetch.setLRSSizeAlgorithm(LRSSizeAlgorithm.LAST); 677 List<?> resultList = q.getResultList(); 678 List<Object[]> objectArrList = (List<Object[]>) resultList; 679 List<WorkflowJobBean> wfBeansList = new ArrayList<WorkflowJobBean>(); 680 681 for (Object[] arr : objectArrList) { 682 WorkflowJobBean ww = getBeanForWorkflowFromArray(arr); 683 wfBeansList.add(ww); 684 } 685 686 realLen = ((Long) qTotal.getSingleResult()).intValue(); 687 688 return new WorkflowsInfo(wfBeansList, start, len, realLen); 689 } 690 }); 691 return workFlowsInfo; 692 693 } 694 695 /** 696 * Load the Workflow and all Action details and return a WorkflowJobBean. Workflow Instance is not loaded 697 * 698 * @param id Workflow Id 699 * @return Workflow Bean 700 * @throws StoreException If Workflow doesn't exist 701 */ 702 public WorkflowJobBean getWorkflowInfo(final String id) throws StoreException { 703 ParamChecker.notEmpty(id, "WorkflowID"); 704 WorkflowJobBean wfBean = doOperation("getWorkflowInfo", new Callable<WorkflowJobBean>() { 705 public WorkflowJobBean call() throws SQLException, StoreException, InterruptedException { 706 WorkflowJobBean wfBean = null; 707 wfBean = getWorkflowforInfo(id, false); 708 if (wfBean == null) { 709 throw new StoreException(ErrorCode.E0604, id); 710 } 711 else { 712 wfBean.setActions(getActionsForWorkflow(id, false)); 713 } 714 return wfBean; 715 } 716 }); 717 return wfBean; 718 } 719 720 /** 721 * Load the Workflow and subset Actions details and return a WorkflowJobBean. Workflow Instance is not loaded 722 * 723 * @param id Workflow Id 724 * @param start offset for select statement for actions 725 * @param len number of Workflow Actions to be returned 726 * @return Workflow Bean 727 * @throws StoreException If Workflow doesn't exist 728 */ 729 public WorkflowJobBean getWorkflowInfoWithActionsSubset(final String id, final int start, final int len) throws StoreException { 730 ParamChecker.notEmpty(id, "WorkflowID"); 731 WorkflowJobBean wfBean = doOperation("getWorkflowInfo", new Callable<WorkflowJobBean>() { 732 public WorkflowJobBean call() throws SQLException, StoreException, InterruptedException { 733 WorkflowJobBean wfBean = null; 734 wfBean = getWorkflowforInfo(id, false); 735 if (wfBean == null) { 736 throw new StoreException(ErrorCode.E0604, id); 737 } 738 else { 739 wfBean.setActions(getActionsSubsetForWorkflow(id, start, len)); 740 } 741 return wfBean; 742 } 743 }); 744 return wfBean; 745 } 746 747 /** 748 * Get the Workflow ID with given external ID which will be assigned for the subworkflows. 749 * 750 * @param externalId external ID 751 * @return Workflow ID 752 * @throws StoreException if there is no job with external ID 753 */ 754 public String getWorkflowIdForExternalId(final String externalId) throws StoreException { 755 ParamChecker.notEmpty(externalId, "externalId"); 756 String wfId = doOperation("getWorkflowIdForExternalId", new Callable<String>() { 757 public String call() throws SQLException, StoreException { 758 String id = ""; 759 Query q = entityManager.createNamedQuery("GET_WORKFLOW_ID_FOR_EXTERNAL_ID"); 760 q.setParameter("externalId", externalId); 761 List<String> w = q.getResultList(); 762 if (w.size() == 0) { 763 id = ""; 764 } 765 else { 766 int index = w.size() - 1; 767 id = w.get(index); 768 } 769 return id; 770 } 771 }); 772 return wfId; 773 } 774 775 private static final long DAY_IN_MS = 24 * 60 * 60 * 1000; 776 777 /** 778 * Purge the Workflows Completed older than given days. 779 * 780 * @param olderThanDays number of days for which to preserve the workflows 781 * @throws StoreException 782 */ 783 public void purge(final long olderThanDays, final int limit) throws StoreException { 784 doOperation("purge", new Callable<Void>() { 785 public Void call() throws SQLException, StoreException, WorkflowException { 786 Timestamp maxEndTime = new Timestamp(System.currentTimeMillis() - (olderThanDays * DAY_IN_MS)); 787 Query q = entityManager.createNamedQuery("GET_COMPLETED_WORKFLOWS_OLDER_THAN"); 788 q.setParameter("endTime", maxEndTime); 789 q.setMaxResults(limit); 790 List<WorkflowJobBean> workflows = q.getResultList(); 791 int actionDeleted = 0; 792 if (workflows.size() != 0) { 793 for (WorkflowJobBean w : workflows) { 794 String wfId = w.getId(); 795 entityManager.remove(w); 796 Query g = entityManager.createNamedQuery("DELETE_ACTIONS_FOR_WORKFLOW"); 797 g.setParameter("wfId", wfId); 798 actionDeleted += g.executeUpdate(); 799 } 800 } 801 XLog.getLog(getClass()).debug("ENDED Workflow Purge deleted jobs :" + workflows.size() + " and actions " 802 + actionDeleted); 803 return null; 804 } 805 }); 806 } 807 808 private <V> V doOperation(String name, Callable<V> command) throws StoreException { 809 try { 810 Instrumentation.Cron cron = new Instrumentation.Cron(); 811 cron.start(); 812 V retVal; 813 try { 814 retVal = command.call(); 815 } 816 finally { 817 cron.stop(); 818 } 819 Services.get().get(InstrumentationService.class).get().addCron(INSTR_GROUP, name, cron); 820 return retVal; 821 } 822 catch (StoreException ex) { 823 throw ex; 824 } 825 catch (SQLException ex) { 826 throw new StoreException(ErrorCode.E0611, name, ex.getMessage(), ex); 827 } 828 catch (Exception e) { 829 throw new StoreException(ErrorCode.E0607, name, e.getMessage(), e); 830 } 831 } 832 833 private WorkflowJobBean getWorkflowOnly(final String id, boolean locking) throws SQLException, 834 InterruptedException, StoreException { 835 WorkflowJobBean wfBean = null; 836 Query q = entityManager.createNamedQuery("GET_WORKFLOW"); 837 /* 838 * if (locking) { // q.setHint("openjpa.FetchPlan.ReadLockMode","READ"); 839 * OpenJPAQuery oq = OpenJPAPersistence.cast(q); FetchPlan fetch = 840 * oq.getFetchPlan(); fetch.setReadLockMode(LockModeType.WRITE); 841 * fetch.setLockTimeout(-1); // unlimited } 842 */ 843 q.setParameter("id", id); 844 List<WorkflowJobBean> w = q.getResultList(); 845 if (w.size() > 0) { 846 wfBean = w.get(0); 847 } 848 return wfBean; 849 // return getBeanForRunningWorkflow(wfBean); 850 } 851 852 private WorkflowJobBean getWorkflowforInfo(final String id, boolean locking) throws SQLException, 853 InterruptedException, StoreException { 854 WorkflowJobBean wfBean = null; 855 Query q = entityManager.createNamedQuery("GET_WORKFLOW"); 856 q.setParameter("id", id); 857 List<WorkflowJobBean> w = q.getResultList(); 858 if (w.size() > 0) { 859 wfBean = w.get(0); 860 return getBeanForRunningWorkflow(wfBean); 861 } 862 return null; 863 } 864 865 private WorkflowJobBean getBeanForRunningWorkflow(WorkflowJobBean w) throws SQLException { 866 WorkflowJobBean wfBean = new WorkflowJobBean(); 867 wfBean.setId(w.getId()); 868 wfBean.setAppName(w.getAppName()); 869 wfBean.setAppPath(w.getAppPath()); 870 wfBean.setConfBlob(w.getConfBlob()); 871 wfBean.setGroup(w.getGroup()); 872 wfBean.setRun(w.getRun()); 873 wfBean.setUser(w.getUser()); 874 wfBean.setCreatedTime(w.getCreatedTime()); 875 wfBean.setEndTime(w.getEndTime()); 876 wfBean.setExternalId(w.getExternalId()); 877 wfBean.setLastModifiedTime(w.getLastModifiedTime()); 878 wfBean.setLogToken(w.getLogToken()); 879 wfBean.setProtoActionConfBlob(w.getProtoActionConfBlob()); 880 wfBean.setSlaXmlBlob(w.getSlaXmlBlob()); 881 wfBean.setStartTime(w.getStartTime()); 882 wfBean.setStatus(w.getStatus()); 883 wfBean.setWfInstanceBlob(w.getWfInstanceBlob()); 884 return wfBean; 885 } 886 887 private WorkflowJobBean getBeanForWorkflowFromArray(Object[] arr) { 888 889 WorkflowJobBean wfBean = new WorkflowJobBean(); 890 wfBean.setId((String) arr[0]); 891 if (arr[1] != null) { 892 wfBean.setAppName((String) arr[1]); 893 } 894 if (arr[2] != null) { 895 wfBean.setStatus(Status.valueOf((String) arr[2])); 896 } 897 if (arr[3] != null) { 898 wfBean.setRun((Integer) arr[3]); 899 } 900 if (arr[4] != null) { 901 wfBean.setUser((String) arr[4]); 902 } 903 if (arr[5] != null) { 904 wfBean.setGroup((String) arr[5]); 905 } 906 if (arr[6] != null) { 907 wfBean.setCreatedTime((Timestamp) arr[6]); 908 } 909 if (arr[7] != null) { 910 wfBean.setStartTime((Timestamp) arr[7]); 911 } 912 if (arr[8] != null) { 913 wfBean.setLastModifiedTime((Timestamp) arr[8]); 914 } 915 if (arr[9] != null) { 916 wfBean.setEndTime((Timestamp) arr[9]); 917 } 918 return wfBean; 919 } 920 921 private WorkflowActionBean getBeanForRunningAction(WorkflowActionBean a) throws SQLException { 922 if (a != null) { 923 WorkflowActionBean action = new WorkflowActionBean(); 924 action.setId(a.getId()); 925 action.setConfBlob(a.getConfBlob()); 926 action.setConsoleUrl(a.getConsoleUrl()); 927 action.setDataBlob(a.getDataBlob()); 928 action.setStatsBlob(a.getStatsBlob()); 929 action.setExternalChildIDsBlob(a.getExternalChildIDsBlob()); 930 action.setErrorInfo(a.getErrorCode(), a.getErrorMessage()); 931 action.setExternalId(a.getExternalId()); 932 action.setExternalStatus(a.getExternalStatus()); 933 action.setName(a.getName()); 934 action.setCred(a.getCred()); 935 action.setRetries(a.getRetries()); 936 action.setTrackerUri(a.getTrackerUri()); 937 action.setTransition(a.getTransition()); 938 action.setType(a.getType()); 939 action.setEndTime(a.getEndTime()); 940 action.setExecutionPath(a.getExecutionPath()); 941 action.setLastCheckTime(a.getLastCheckTime()); 942 action.setLogToken(a.getLogToken()); 943 if (a.isPending() == true) { 944 action.setPending(); 945 } 946 action.setPendingAge(a.getPendingAge()); 947 action.setSignalValue(a.getSignalValue()); 948 action.setSlaXmlBlob(a.getSlaXmlBlob()); 949 action.setStartTime(a.getStartTime()); 950 action.setStatus(a.getStatus()); 951 action.setJobId(a.getWfId()); 952 action.setUserRetryCount(a.getUserRetryCount()); 953 action.setUserRetryInterval(a.getUserRetryInterval()); 954 action.setUserRetryMax(a.getUserRetryMax()); 955 return action; 956 } 957 return null; 958 } 959}