| 1 5 package com.opensymphony.workflow; 6 7 import com.opensymphony.module.propertyset.PropertySet; 8 import com.opensymphony.module.propertyset.PropertySetManager; 9 10 import com.opensymphony.util.ClassLoaderUtil; 11 import com.opensymphony.util.TextUtils; 12 13 import com.opensymphony.workflow.config.Configuration; 14 import com.opensymphony.workflow.config.DefaultConfiguration; 15 import com.opensymphony.workflow.loader.*; 16 import com.opensymphony.workflow.query.WorkflowExpressionQuery; 17 import com.opensymphony.workflow.query.WorkflowQuery; 18 import com.opensymphony.workflow.spi.*; 19 import com.opensymphony.workflow.util.ScriptVariableParser; 20 import com.opensymphony.workflow.util.beanshell.BeanShellCondition; 21 import com.opensymphony.workflow.util.beanshell.BeanShellFunctionProvider; 22 import com.opensymphony.workflow.util.beanshell.BeanShellRegister; 23 import com.opensymphony.workflow.util.beanshell.BeanShellValidator; 24 import com.opensymphony.workflow.util.bsf.BSFCondition; 25 import com.opensymphony.workflow.util.bsf.BSFFunctionProvider; 26 import com.opensymphony.workflow.util.bsf.BSFRegister; 27 import com.opensymphony.workflow.util.bsf.BSFValidator; 28 import com.opensymphony.workflow.util.ejb.local.LocalEJBCondition; 29 import com.opensymphony.workflow.util.ejb.local.LocalEJBFunctionProvider; 30 import com.opensymphony.workflow.util.ejb.local.LocalEJBRegister; 31 import com.opensymphony.workflow.util.ejb.local.LocalEJBValidator; 32 import com.opensymphony.workflow.util.ejb.remote.RemoteEJBCondition; 33 import com.opensymphony.workflow.util.ejb.remote.RemoteEJBFunctionProvider; 34 import com.opensymphony.workflow.util.ejb.remote.RemoteEJBRegister; 35 import com.opensymphony.workflow.util.ejb.remote.RemoteEJBValidator; 36 import com.opensymphony.workflow.util.jndi.JNDICondition; 37 import com.opensymphony.workflow.util.jndi.JNDIFunctionProvider; 38 import com.opensymphony.workflow.util.jndi.JNDIRegister; 39 import com.opensymphony.workflow.util.jndi.JNDIValidator; 40 41 import org.apache.commons.logging.Log; 42 import org.apache.commons.logging.LogFactory; 43 44 import java.util.*; 45 46 47 53 public class AbstractWorkflow implements Workflow { 54 56 private static final Log log = LogFactory.getLog(AbstractWorkflow.class); 57 58 60 protected WorkflowContext context; 61 private Configuration configuration; 62 63 65 69 public int[] getAvailableActions(long id) { 70 return getAvailableActions(id, new HashMap()); 71 } 72 73 82 public int[] getAvailableActions(long id, Map inputs) { 83 try { 84 WorkflowStore store = getPersistence(); 85 WorkflowEntry entry = store.findEntry(id); 86 87 if (entry == null) { 88 throw new IllegalArgumentException ("No such workflow id " + id); 89 } 90 91 if (entry.getState() != WorkflowEntry.ACTIVATED) { 92 return new int[0]; 93 } 94 95 WorkflowDescriptor wf = getConfiguration().getWorkflow(entry.getWorkflowName()); 96 97 if (wf == null) { 98 throw new IllegalArgumentException ("No such workflow " + entry.getWorkflowName()); 99 } 100 101 List l = new ArrayList(); 102 PropertySet ps = store.getPropertySet(id); 103 Map transientVars = (inputs == null) ? new HashMap() : new HashMap(inputs); 104 Collection currentSteps = store.findCurrentSteps(id); 105 106 populateTransientMap(entry, transientVars, wf.getRegisters(), new Integer (0), currentSteps); 107 108 List globalActions = wf.getGlobalActions(); 110 111 for (Iterator iterator = globalActions.iterator(); 112 iterator.hasNext();) { 113 ActionDescriptor action = (ActionDescriptor) iterator.next(); 114 RestrictionDescriptor restriction = action.getRestriction(); 115 List conditions = null; 116 117 if (restriction != null) { 118 conditions = restriction.getConditions(); 119 } 120 121 if (passesConditions(null, conditions, transientVars, ps, 0)) { 123 l.add(new Integer (action.getId())); 124 } 125 } 126 127 for (Iterator iterator = currentSteps.iterator(); 129 iterator.hasNext();) { 130 Step step = (Step) iterator.next(); 131 l.addAll(getAvailableActionsForStep(wf, step, transientVars, ps)); 132 } 133 134 int[] actions = new int[l.size()]; 135 136 for (int i = 0; i < actions.length; i++) { 137 actions[i] = ((Integer ) l.get(i)).intValue(); 138 } 139 140 return actions; 141 } catch (Exception e) { 142 log.error("Error checking available actions", e); 143 144 return new int[0]; 145 } 146 } 147 148 151 public void setConfiguration(Configuration configuration) { 152 this.configuration = configuration; 153 } 154 155 162 public Configuration getConfiguration() { 163 Configuration config = (configuration != null) ? configuration : DefaultConfiguration.INSTANCE; 164 165 if (!config.isInitialized()) { 166 try { 167 config.load(null); 168 } catch (FactoryException e) { 169 log.fatal("Error initialising configuration", e); 170 171 return null; 173 } 174 } 175 176 return config; 177 } 178 179 182 public List getCurrentSteps(long id) { 183 try { 184 WorkflowStore store = getPersistence(); 185 186 return store.findCurrentSteps(id); 187 } catch (StoreException e) { 188 log.error("Error checking current steps for instance #" + id, e); 189 190 return Collections.EMPTY_LIST; 191 } 192 } 193 194 197 public int getEntryState(long id) { 198 try { 199 WorkflowStore store = getPersistence(); 200 201 return store.findEntry(id).getState(); 202 } catch (StoreException e) { 203 log.error("Error checking instance state for instance #" + id, e); 204 } 205 206 return WorkflowEntry.UNKNOWN; 207 } 208 209 212 public List getHistorySteps(long id) { 213 try { 214 WorkflowStore store = getPersistence(); 215 216 return store.findHistorySteps(id); 217 } catch (StoreException e) { 218 log.error("Error getting history steps for instance #" + id, e); 219 } 220 221 return Collections.EMPTY_LIST; 222 } 223 224 227 public Properties getPersistenceProperties() { 228 Properties p = new Properties(); 229 Iterator iter = getConfiguration().getPersistenceArgs().entrySet().iterator(); 230 231 while (iter.hasNext()) { 232 Map.Entry entry = (Map.Entry) iter.next(); 233 p.setProperty((String ) entry.getKey(), (String ) entry.getValue()); 234 } 235 236 return p; 237 } 238 239 244 public PropertySet getPropertySet(long id) { 245 PropertySet ps = null; 246 247 try { 248 ps = getPersistence().getPropertySet(id); 249 } catch (StoreException e) { 250 log.error("Error getting propertyset for instance #" + id, e); 251 } 252 253 return ps; 254 } 255 256 259 public List getSecurityPermissions(long id) { 260 try { 261 WorkflowStore store = getPersistence(); 262 WorkflowEntry entry = store.findEntry(id); 263 WorkflowDescriptor wf = getConfiguration().getWorkflow(entry.getWorkflowName()); 264 265 PropertySet ps = store.getPropertySet(id); 266 Map transientVars = new HashMap(); 267 Collection currentSteps = store.findCurrentSteps(id); 268 populateTransientMap(entry, transientVars, wf.getRegisters(), null, currentSteps); 269 270 List s = new ArrayList(); 271 272 for (Iterator interator = currentSteps.iterator(); 273 interator.hasNext();) { 274 Step step = (Step) interator.next(); 275 276 int stepId = step.getStepId(); 277 278 StepDescriptor xmlStep = wf.getStep(stepId); 279 280 List securities = xmlStep.getPermissions(); 281 282 for (Iterator iterator2 = securities.iterator(); 283 iterator2.hasNext();) { 284 PermissionDescriptor security = (PermissionDescriptor) iterator2.next(); 285 286 if (passesConditions(null, security.getRestriction().getConditions(), transientVars, ps, xmlStep.getId())) { 289 s.add(security.getName()); 290 } 291 } 292 } 293 294 return s; 295 } catch (Exception e) { 296 log.error("Error getting security permissions for instance #" + id, e); 297 } 298 299 return Collections.EMPTY_LIST; 300 } 301 302 309 public WorkflowDescriptor getWorkflowDescriptor(String workflowName) { 310 try { 311 return getConfiguration().getWorkflow(workflowName); 312 } catch (FactoryException e) { 313 log.error("Error loading workflow " + workflowName, e); 314 } 315 316 return null; 317 } 318 319 322 public String getWorkflowName(long id) { 323 try { 324 WorkflowStore store = getPersistence(); 325 WorkflowEntry entry = store.findEntry(id); 326 327 if (entry != null) { 328 return entry.getWorkflowName(); 329 } 330 } catch (StoreException e) { 331 log.error("Error getting instance name for instance #" + id, e); 332 } 333 334 return null; 335 } 336 337 342 public String [] getWorkflowNames() { 343 try { 344 return getConfiguration().getWorkflowNames(); 345 } catch (FactoryException e) { 346 log.error("Error getting workflow names", e); 347 } 348 349 return new String [0]; 350 } 351 352 355 public boolean canInitialize(String workflowName, int initialAction) { 356 return canInitialize(workflowName, initialAction, null); 357 } 358 359 366 public boolean canInitialize(String workflowName, int initialAction, Map inputs) { 367 final String mockWorkflowName = workflowName; 368 WorkflowEntry mockEntry = new WorkflowEntry() { 369 public long getId() { 370 return 0; 371 } 372 373 public String getWorkflowName() { 374 return mockWorkflowName; 375 } 376 377 public boolean isInitialized() { 378 return false; 379 } 380 381 public int getState() { 382 return WorkflowEntry.CREATED; 383 } 384 }; 385 386 PropertySet ps = PropertySetManager.getInstance("memory", null); 388 Map transientVars = new HashMap(); 389 390 if (inputs != null) { 391 transientVars.putAll(inputs); 392 } 393 394 try { 395 populateTransientMap(mockEntry, transientVars, Collections.EMPTY_LIST, new Integer (initialAction), Collections.EMPTY_LIST); 396 397 return canInitialize(workflowName, initialAction, transientVars, ps); 398 } catch (InvalidActionException e) { 399 log.error(e.getMessage()); 400 401 return false; 402 } catch (WorkflowException e) { 403 log.error("Error checking canInitialize", e); 404 405 return false; 406 } 407 } 408 409 412 public boolean canModifyEntryState(long id, int newState) { 413 try { 414 WorkflowStore store = getPersistence(); 415 WorkflowEntry entry = store.findEntry(id); 416 int currentState = entry.getState(); 417 boolean result = false; 418 419 switch (newState) { 420 case WorkflowEntry.CREATED: 421 result = false; 422 423 case WorkflowEntry.ACTIVATED: 424 425 if ((currentState == WorkflowEntry.CREATED) || (currentState == WorkflowEntry.SUSPENDED)) { 426 result = true; 427 } 428 429 break; 430 431 case WorkflowEntry.SUSPENDED: 432 433 if (currentState == WorkflowEntry.ACTIVATED) { 434 result = true; 435 } 436 437 break; 438 439 case WorkflowEntry.KILLED: 440 441 if ((currentState == WorkflowEntry.CREATED) || (currentState == WorkflowEntry.ACTIVATED) || (currentState == WorkflowEntry.SUSPENDED)) { 442 result = true; 443 } 444 445 break; 446 447 default: 448 result = false; 449 450 break; 451 } 452 453 return result; 454 } catch (StoreException e) { 455 log.error("Error checking state modifiable for instance #" + id, e); 456 } 457 458 return false; 459 } 460 461 public void changeEntryState(long id, int newState) throws WorkflowException { 462 WorkflowStore store = getPersistence(); 463 WorkflowEntry entry = store.findEntry(id); 464 465 if (entry.getState() == newState) { 466 return; 467 } 468 469 if (canModifyEntryState(id, newState)) { 470 if ((newState == WorkflowEntry.KILLED) || (newState == WorkflowEntry.COMPLETED)) { 471 Collection currentSteps = getCurrentSteps(id); 472 473 if (currentSteps.size() > 0) { 474 completeEntry(id, currentSteps); 475 } 476 } 477 478 store.setEntryState(id, newState); 479 } else { 480 throw new InvalidEntryStateException("Can't transition workflow instance #" + id + ". Current state is " + entry.getState() + ", requested state is " + newState); 481 } 482 483 if (log.isDebugEnabled()) { 484 log.debug(entry.getId() + " : State is now : " + entry.getState()); 485 } 486 } 487 488 public void doAction(long id, int actionId, Map inputs) throws WorkflowException { 489 WorkflowStore store = getPersistence(); 490 WorkflowEntry entry = store.findEntry(id); 491 492 if (entry.getState() != WorkflowEntry.ACTIVATED) { 493 return; 494 } 495 496 WorkflowDescriptor wf = getConfiguration().getWorkflow(entry.getWorkflowName()); 497 498 List currentSteps = store.findCurrentSteps(id); 499 ActionDescriptor action = null; 500 501 PropertySet ps = store.getPropertySet(id); 502 Map transientVars = new HashMap(); 503 504 if (inputs != null) { 505 transientVars.putAll(inputs); 506 } 507 508 populateTransientMap(entry, transientVars, wf.getRegisters(), new Integer (actionId), currentSteps); 509 510 boolean validAction = false; 511 512 for (Iterator gIter = wf.getGlobalActions().iterator(); 514 !validAction && gIter.hasNext();) { 515 ActionDescriptor actionDesc = (ActionDescriptor) gIter.next(); 516 517 if (actionDesc.getId() == actionId) { 518 action = actionDesc; 519 520 if (isActionAvailable(action, transientVars, ps, 0)) { 521 validAction = true; 522 } 523 } 524 } 525 526 for (Iterator iter = currentSteps.iterator(); 527 !validAction && iter.hasNext();) { 528 Step step = (Step) iter.next(); 529 StepDescriptor s = wf.getStep(step.getStepId()); 530 531 for (Iterator iterator = s.getActions().iterator(); 532 !validAction && iterator.hasNext();) { 533 ActionDescriptor actionDesc = (ActionDescriptor) iterator.next(); 534 535 if (actionDesc.getId() == actionId) { 536 action = actionDesc; 537 538 if (isActionAvailable(action, transientVars, ps, s.getId())) { 539 validAction = true; 540 } 541 } 542 } 543 } 544 545 if (!validAction) { 546 throw new InvalidActionException("Action " + actionId + " is invalid"); 547 } 548 549 try { 550 if (!transitionWorkflow(entry, currentSteps, store, wf, action, transientVars, inputs, ps)) { 552 checkImplicitFinish(id); 553 } 554 } catch (WorkflowException e) { 555 context.setRollbackOnly(); 556 throw e; 557 } 558 } 559 560 public void executeTriggerFunction(long id, int triggerId) throws WorkflowException { 561 WorkflowStore store = getPersistence(); 562 WorkflowEntry entry = store.findEntry(id); 563 564 if (entry == null) { 565 log.warn("Cannot execute trigger #" + triggerId + " on non-existent workflow id#" + id); 566 567 return; 568 } 569 570 WorkflowDescriptor wf = getConfiguration().getWorkflow(entry.getWorkflowName()); 571 572 PropertySet ps = store.getPropertySet(id); 573 Map transientVars = new HashMap(); 574 populateTransientMap(entry, transientVars, wf.getRegisters(), null, store.findCurrentSteps(id)); 575 executeFunction(wf.getTriggerFunction(triggerId), transientVars, ps); 576 } 577 578 public long initialize(String workflowName, int initialAction, Map inputs) throws InvalidRoleException, InvalidInputException, WorkflowException { 579 WorkflowDescriptor wf = getConfiguration().getWorkflow(workflowName); 580 581 WorkflowStore store = getPersistence(); 582 WorkflowEntry entry = store.createEntry(workflowName); 583 584 PropertySet ps = store.getPropertySet(entry.getId()); 586 Map transientVars = new HashMap(); 587 588 if (inputs != null) { 589 transientVars.putAll(inputs); 590 } 591 592 populateTransientMap(entry, transientVars, wf.getRegisters(), new Integer (initialAction), Collections.EMPTY_LIST); 593 594 if (!canInitialize(workflowName, initialAction, transientVars, ps)) { 595 context.setRollbackOnly(); 596 throw new InvalidRoleException("You are restricted from initializing this workflow"); 597 } 598 599 ActionDescriptor action = wf.getInitialAction(initialAction); 600 601 try { 602 transitionWorkflow(entry, Collections.EMPTY_LIST, store, wf, action, transientVars, inputs, ps); 603 } catch (WorkflowException e) { 604 context.setRollbackOnly(); 605 throw e; 606 } 607 608 long entryId = entry.getId(); 609 610 return entryId; 613 } 614 615 618 public List query(WorkflowQuery query) throws StoreException { 619 return getPersistence().query(query); 620 } 621 622 625 public List query(WorkflowExpressionQuery query) throws WorkflowException { 626 return getPersistence().query(query); 627 } 628 629 632 public boolean removeWorkflowDescriptor(String workflowName) throws FactoryException { 633 return getConfiguration().removeWorkflow(workflowName); 634 } 635 636 639 public boolean saveWorkflowDescriptor(String workflowName, WorkflowDescriptor descriptor, boolean replace) throws FactoryException { 640 boolean success = getConfiguration().saveWorkflow(workflowName, descriptor, replace); 641 642 return success; 643 } 644 645 protected List getAvailableActionsForStep(WorkflowDescriptor wf, Step step, Map transientVars, PropertySet ps) throws WorkflowException { 646 List l = new ArrayList(); 647 StepDescriptor s = wf.getStep(step.getStepId()); 648 649 if (s == null) { 650 log.warn("getAvailableActionsForStep called for non-existent step Id #" + step.getStepId()); 651 652 return l; 653 } 654 655 List actions = s.getActions(); 656 657 if ((actions == null) || (actions.size() == 0)) { 658 return l; 659 } 660 661 for (Iterator iterator2 = actions.iterator(); iterator2.hasNext();) { 662 ActionDescriptor action = (ActionDescriptor) iterator2.next(); 663 RestrictionDescriptor restriction = action.getRestriction(); 664 List conditions = null; 665 666 if (restriction != null) { 667 conditions = restriction.getConditions(); 668 } 669 670 if (passesConditions(null, conditions, Collections.unmodifiableMap(transientVars), ps, s.getId())) { 671 l.add(new Integer (action.getId())); 672 } 673 } 674 675 return l; 676 } 677 678 protected int[] getAvailableAutoActions(long id, Map inputs) { 679 try { 680 WorkflowStore store = getPersistence(); 681 WorkflowEntry entry = store.findEntry(id); 682 683 if (entry == null) { 684 throw new IllegalArgumentException ("No such workflow id " + id); 685 } 686 687 if (entry.getState() != WorkflowEntry.ACTIVATED) { 688 log.debug("--> state is " + entry.getState()); 689 690 return new int[0]; 691 } 692 693 WorkflowDescriptor wf = getConfiguration().getWorkflow(entry.getWorkflowName()); 694 695 if (wf == null) { 696 throw new IllegalArgumentException ("No such workflow " + entry.getWorkflowName()); 697 } 698 699 List l = new ArrayList(); 700 PropertySet ps = store.getPropertySet(id); 701 Map transientVars = (inputs == null) ? new HashMap() : new HashMap(inputs); 702 Collection currentSteps = store.findCurrentSteps(id); 703 704 populateTransientMap(entry, transientVars, wf.getRegisters(), new Integer (0), currentSteps); 705 706 List globalActions = wf.getGlobalActions(); 708 709 for (Iterator iterator = globalActions.iterator(); 710 iterator.hasNext();) { 711 ActionDescriptor action = (ActionDescriptor) iterator.next(); 712 713 if (action.getAutoExecute()) { 714 if (isActionAvailable(action, transientVars, ps, 0)) { 715 l.add(new Integer (action.getId())); 716 } 717 } 718 } 719 720 for (Iterator iterator = currentSteps.iterator(); 722 iterator.hasNext();) { 723 Step step = (Step) iterator.next(); 724 l.addAll(getAvailableAutoActionsForStep(wf, step, transientVars, ps)); 725 } 726 727 int[] actions = new int[l.size()]; 728 729 for (int i = 0; i < actions.length; i++) { 730 actions[i] = ((Integer ) l.get(i)).intValue(); 731 } 732 733 return actions; 734 } catch (Exception e) { 735 log.error("Error checking available actions", e); 736 737 return new int[0]; 738 } 739 } 740 741 744 protected List getAvailableAutoActionsForStep(WorkflowDescriptor wf, Step step, Map transientVars, PropertySet ps) throws WorkflowException { 745 List l = new ArrayList(); 746 StepDescriptor s = wf.getStep(step.getStepId()); 747 748 if (s == null) { 749 log.warn("getAvailableAutoActionsForStep called for non-existent step Id #" + step.getStepId()); 750 751 return l; 752 } 753 754 List actions = s.getActions(); 755 756 if ((actions == null) || (actions.size() == 0)) { 757 return l; 758 } 759 760 for (Iterator iterator2 = actions.iterator(); iterator2.hasNext();) { 761 ActionDescriptor action = (ActionDescriptor) iterator2.next(); 762 763 if (action.getAutoExecute()) { 765 if (isActionAvailable(action, transientVars, ps, s.getId())) { 766 l.add(new Integer (action.getId())); 767 } 768 } 769 } 770 771 return l; 772 } 773 774 protected WorkflowStore getPersistence() throws StoreException { 775 return getConfiguration().getWorkflowStore(); 776 } 777 778 protected void checkImplicitFinish(long id) throws WorkflowException { 779 WorkflowStore store = getPersistence(); 780 WorkflowEntry entry = store.findEntry(id); 781 782 WorkflowDescriptor wf = getConfiguration().getWorkflow(entry.getWorkflowName()); 783 784 Collection currentSteps = store.findCurrentSteps(id); 785 786 boolean isCompleted = true; 787 788 for (Iterator iterator = currentSteps.iterator(); iterator.hasNext();) { 789 Step step = (Step) iterator.next(); 790 StepDescriptor stepDes = wf.getStep(step.getStepId()); 791 792 if (stepDes.getActions().size() > 0) { 794 isCompleted = false; 795 } 796 } 797 798 if (isCompleted == true) { 799 completeEntry(id, currentSteps); 800 } 801 } 802 803 806 protected void completeEntry(long id, Collection currentSteps) throws StoreException { 807 getPersistence().setEntryState(id, WorkflowEntry.COMPLETED); 808 809 Iterator i = new ArrayList(currentSteps).iterator(); 810 811 while (i.hasNext()) { 812 Step step = (Step) i.next(); 813 getPersistence().moveToHistory(step); 814 } 815 } 816 817 protected Object loadObject(String clazz) { 818 try { 819 return ClassLoaderUtil.loadClass(clazz.trim(), getClass()).newInstance(); 820 } catch (Exception e) { 821 log.error("Could not load object '" + clazz + "'", e); 822 823 return null; 824 } 825 } 826 827 protected boolean passesCondition(ConditionDescriptor conditionDesc, Map transientVars, PropertySet ps, int currentStepId) throws WorkflowException { 828 String type = conditionDesc.getType(); 829 830 Map args = new HashMap(conditionDesc.getArgs()); 831 832 for (Iterator iterator = args.entrySet().iterator(); 833 iterator.hasNext();) { 834 Map.Entry mapEntry = (Map.Entry) iterator.next(); 835 mapEntry.setValue(ScriptVariableParser.translateVariables((String ) mapEntry.getValue(), transientVars, ps)); 836 } 837 838 if (currentStepId != -1) { 839 Object stepId = args.get("stepId"); 840 841 if ((stepId != null) && stepId.equals("-1")) { 842 args.put("stepId", String.valueOf(currentStepId)); 843 } 844 } 845 846 String clazz; 847 848 if ("remote-ejb".equals(type)) { 849 clazz = RemoteEJBCondition.class.getName(); 850 } else if ("local-ejb".equals(type)) { 851 clazz = LocalEJBCondition.class.getName(); 852 } else if ("jndi".equals(type)) { 853 clazz = JNDICondition.class.getName(); 854 } else if ("bsf".equals(type)) { 855 clazz = BSFCondition.class.getName(); 856 } else if ("beanshell".equals(type)) { 857 clazz = BeanShellCondition.class.getName(); 858 } else { 859 clazz = (String ) args.get(CLASS_NAME); 860 } 861 862 Condition condition = (Condition) loadObject(clazz); 863 864 if (condition == null) { 865 String message = "Could not load Condition: " + clazz; 866 throw new WorkflowException(message); 867 } 868 869 try { 870 boolean passed = condition.passesCondition(transientVars, args, ps); 871 872 if (conditionDesc.isNegate()) { 873 passed = !passed; 874 } 875 876 return passed; 877 } catch (Exception e) { 878 context.setRollbackOnly(); 879 880 if (e instanceof WorkflowException) { 881
|