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 throw (WorkflowException) e; 882 } 883 884 throw new WorkflowException("Unknown exception encountered when trying condition: " + clazz, e); 885 } 886 } 887 888 protected boolean passesConditions(String conditionType, List conditions, Map transientVars, PropertySet ps, int currentStepId) throws WorkflowException { 889 if ((conditions == null) || (conditions.size() == 0)) { 890 return true; 891 } 892 893 boolean and = "AND".equals(conditionType); 894 boolean or = !and; 895 896 for (Iterator iterator = conditions.iterator(); iterator.hasNext();) { 897 AbstractDescriptor descriptor = (AbstractDescriptor) iterator.next(); 898 boolean result; 899 900 if (descriptor instanceof ConditionsDescriptor) { 901 ConditionsDescriptor conditionsDescriptor = (ConditionsDescriptor) descriptor; 902 result = passesConditions(conditionsDescriptor.getType(), conditionsDescriptor.getConditions(), transientVars, ps, currentStepId); 903 } else { 904 result = passesCondition((ConditionDescriptor) descriptor, transientVars, ps, currentStepId); 905 } 906 907 if (and && !result) { 908 return false; 909 } else if (or && result) { 910 return true; 911 } 912 } 913 914 if (and) { 915 return true; 916 } else if (or) { 917 return false; 918 } else { 919 return false; 920 } 921 } 922 923 protected void populateTransientMap(WorkflowEntry entry, Map transientVars, List registers, Integer actionId, Collection currentSteps) throws WorkflowException { 924 transientVars.put("context", context); 925 transientVars.put("entry", entry); 926 transientVars.put("store", getPersistence()); 927 transientVars.put("descriptor", getConfiguration().getWorkflow(entry.getWorkflowName())); 928 929 if (actionId != null) { 930 transientVars.put("actionId", actionId); 931 } 932 933 transientVars.put("currentSteps", Collections.unmodifiableCollection(currentSteps)); 934 935 for (Iterator iterator = registers.iterator(); iterator.hasNext();) { 937 RegisterDescriptor register = (RegisterDescriptor) iterator.next(); 938 Map args = register.getArgs(); 939 940 String type = register.getType(); 941 String clazz; 942 943 if ("remote-ejb".equals(type)) { 944 clazz = RemoteEJBRegister.class.getName(); 945 } else if ("local-ejb".equals(type)) { 946 clazz = LocalEJBRegister.class.getName(); 947 } else if ("jndi".equals(type)) { 948 clazz = JNDIRegister.class.getName(); 949 } else if ("bsf".equals(type)) { 950 clazz = BSFRegister.class.getName(); 951 } else if ("beanshell".equals(type)) { 952 clazz = BeanShellRegister.class.getName(); 953 } else { 954 clazz = (String ) args.get(CLASS_NAME); 955 } 956 957 Register r = (Register) loadObject(clazz); 958 959 if (r == null) { 960 String message = "Could not load register class: " + clazz; 961 throw new WorkflowException(message); 962 } 963 964 try { 965 transientVars.put(register.getVariableName(), r.registerVariable(context, entry, args)); 966 } catch (Exception e) { 967 context.setRollbackOnly(); 968 969 if (e instanceof WorkflowException) { 970 throw (WorkflowException) e; 971 } 972 973 throw new WorkflowException("An unknown exception occured while registering variable using class: " + clazz, e); 974 } 975 } 976 } 977 978 987 protected void verifyInputs(WorkflowEntry entry, List validators, Map transientVars, PropertySet ps) throws WorkflowException { 988 for (Iterator iterator = validators.iterator(); iterator.hasNext();) { 989 ValidatorDescriptor input = (ValidatorDescriptor) iterator.next(); 990 991 if (input != null) { 992 String type = input.getType(); 993 HashMap args = new HashMap(input.getArgs()); 994 995 for (Iterator iterator2 = args.entrySet().iterator(); 996 iterator2.hasNext();) { 997 Map.Entry mapEntry = (Map.Entry) iterator2.next(); 998 mapEntry.setValue(ScriptVariableParser.translateVariables((String ) mapEntry.getValue(), transientVars, ps)); 999 } 1000 1001 String clazz; 1002 1003 if ("remote-ejb".equals(type)) { 1004 clazz = RemoteEJBValidator.class.getName(); 1005 } else if ("local-ejb".equals(type)) { 1006 clazz = LocalEJBValidator.class.getName(); 1007 } else if ("jndi".equals(type)) { 1008 clazz = JNDIValidator.class.getName(); 1009 } else if ("bsf".equals(type)) { 1010 clazz = BSFValidator.class.getName(); 1011 } else if ("beanshell".equals(type)) { 1012 clazz = BeanShellValidator.class.getName(); 1013 } else { 1014 clazz = (String ) args.get(CLASS_NAME); 1015 } 1016 1017 Validator validator = (Validator) loadObject(clazz); 1018 1019 if (validator == null) { 1020 String message = "Could not load validator class: " + clazz; 1021 throw new WorkflowException(message); 1022 } 1023 1024 try { 1025 validator.validate(transientVars, args, ps); 1026 } catch (InvalidInputException e) { 1027 throw e; 1028 } catch (Exception e) { 1029 context.setRollbackOnly(); 1030 1031 if (e instanceof WorkflowException) { 1032 throw (WorkflowException) e; 1033 } 1034 1035 String message = "An unknown exception occured executing Validator: " + clazz; 1036 throw new WorkflowException(message, e); 1037 } 1038 } 1039 } 1040 } 1041 1042 1047 private boolean isActionAvailable(ActionDescriptor action, Map transientVars, PropertySet ps, int stepId) throws WorkflowException { 1048 if (action == null) { 1049 return false; 1050 } 1051 1052 RestrictionDescriptor restriction = action.getRestriction(); 1053 List conditions = null; 1054 1055 if (restriction != null) { 1056 conditions = restriction.getConditions(); 1057 } 1058 1059 return passesConditions(null, conditions, Collections.unmodifiableMap(transientVars), ps, stepId); 1060 } 1061 1062 private Step getCurrentStep(WorkflowDescriptor wfDesc, int actionId, List currentSteps, Map transientVars, PropertySet ps) throws WorkflowException { 1063 if (currentSteps.size() == 1) { 1064 return (Step) currentSteps.get(0); 1065 } 1066 1067 for (Iterator iterator = currentSteps.iterator(); iterator.hasNext();) { 1068 Step step = (Step) iterator.next(); 1069 ActionDescriptor action = wfDesc.getStep(step.getStepId()).getAction(actionId); 1070 1071 if (isActionAvailable(action, transientVars, ps, step.getStepId())) { 1073 return step; 1074 } 1075 1076 } 1078 1079 return null; 1080 } 1081 1082 private boolean canInitialize(String workflowName, int initialAction, Map transientVars, PropertySet ps) throws WorkflowException { 1083 WorkflowDescriptor wf = getConfiguration().getWorkflow(workflowName); 1084 1085 ActionDescriptor actionDescriptor = wf.getInitialAction(initialAction); 1086 1087 if (actionDescriptor == null) { 1088 throw new InvalidActionException("Invalid Initial Action #" + initialAction); 1089 } 1090 1091 RestrictionDescriptor restriction = actionDescriptor.getRestriction(); 1092 List conditions = null; 1093 1094 if (restriction != null) { 1095 conditions = restriction.getConditions(); 1096 } 1097 1098 return passesConditions(null, conditions, Collections.unmodifiableMap(transientVars), ps, 0); 1099 } 1100 1101 private Step createNewCurrentStep(ResultDescriptor theResult, WorkflowEntry entry, WorkflowStore store, int actionId, Step currentStep, long[] previousIds, Map transientVars, PropertySet ps) throws WorkflowException { 1102 try { 1103 int nextStep = theResult.getStep(); 1104 1105 if (nextStep == -1) { 1106 if (currentStep != null) { 1107 nextStep = currentStep.getStepId(); 1108 } else { 1109 throw new StoreException("Illegal argument: requested new current step same as current step, but current step not specified"); 1110 } 1111 } 1112 1113 if (log.isDebugEnabled()) { 1114 log.debug("Outcome: stepId=" + nextStep + ", status=" + theResult.getStatus() + ", owner=" + theResult.getOwner() + ", actionId=" + actionId + ", currentStep=" + ((currentStep != null) ? currentStep.getStepId() : 0)); 1115 } 1116 1117 if (previousIds == null) { 1118 previousIds = new long[0]; 1119 } 1120 1121 String owner = TextUtils.noNull(theResult.getOwner()); 1122 1123 if (owner.equals("")) { 1124 owner = null; 1125 } else { 1126 Object o = ScriptVariableParser.translateVariables(owner, transientVars, ps); 1127 owner = (o != null) ? o.toString() : null; 1128 } 1129 1130 String oldStatus = theResult.getOldStatus(); 1131 oldStatus = ScriptVariableParser.translateVariables(oldStatus, transientVars, ps).toString(); 1132 1133 String status = theResult.getStatus(); 1134 status = ScriptVariableParser.translateVariables(status, transientVars, ps).toString(); 1135 1136 if (currentStep != null) { 1137 store.markFinished(currentStep, actionId, new Date(), oldStatus, context.getCaller()); 1138 store.moveToHistory(currentStep); 1139 1140 } 1142 1143 Date startDate = new Date(); 1145 Date dueDate = null; 1146 1147 if ((theResult.getDueDate() != null) && (theResult.getDueDate().length() > 0)) { 1148 Object dueDateObject = ScriptVariableParser.translateVariables(theResult.getDueDate(), transientVars, ps); 1149 1150 if (dueDateObject instanceof Date) { 1151 dueDate = (Date) dueDateObject; 1152 } else if (dueDateObject instanceof String ) { 1153 long offset = TextUtils.parseLong((String ) dueDateObject); 1154 1155 if (offset > 0) { 1156 dueDate = new Date(startDate.getTime() + offset); 1157 } 1158 } else if (dueDateObject instanceof Number ) { 1159 Number num = (Number ) dueDateObject; 1160 long offset = num.longValue(); 1161 1162 if (offset > 0) { 1163 dueDate = new Date(startDate.getTime() + offset); 1164 } 1165 } 1166 } 1167 1168 Step newStep = store.createCurrentStep(entry.getId(), nextStep, owner, startDate, dueDate, status, previousIds); 1169 WorkflowDescriptor descriptor = (WorkflowDescriptor) transientVars.get("descriptor"); 1170 List preFunctions = descriptor.getStep(nextStep).getPreFunctions(); 1171 1172 for (Iterator iterator = preFunctions.iterator(); 1173 iterator.hasNext();) { 1174 FunctionDescriptor function = (FunctionDescriptor) iterator.next(); 1175 executeFunction(function, transientVars, ps); 1176 } 1177 1178 return newStep; 1179 } catch (WorkflowException e) { 1180 context.setRollbackOnly(); 1181 throw e; 1182 } 1183 } 1184 1185 1192 private void executeFunction(FunctionDescriptor function, Map transientVars, PropertySet ps) throws WorkflowException { 1193 if (function != null) { 1194 String type = function.getType(); 1195 1196 HashMap args = new HashMap(function.getArgs()); 1197 1198 for (Iterator iterator = args.entrySet().iterator(); 1199 iterator.hasNext();) { 1200 Map.Entry mapEntry = (Map.Entry) iterator.next(); 1201 mapEntry.setValue(ScriptVariableParser.translateVariables((String ) mapEntry.getValue(), transientVars, ps)); 1202 } 1203 1204 String clazz; 1205 1206 if ("remote-ejb".equals(type)) { 1207 clazz = RemoteEJBFunctionProvider.class.getName(); 1208 } else if ("local-ejb".equals(type)) { 1209 clazz = LocalEJBFunctionProvider.class.getName(); 1210 } else if ("jndi".equals(type)) { 1211 clazz = JNDIFunctionProvider.class.getName(); 1212 } else if ("bsf".equals(type)) { 1213 clazz = BSFFunctionProvider.class.getName(); 1214 } else if ("beanshell".equals(type)) { 1215 clazz = BeanShellFunctionProvider.class.getName(); 1216 } else { 1217 clazz = (String ) args.get(CLASS_NAME); 1218 } 1219 1220 FunctionProvider provider = (FunctionProvider) loadObject(clazz); 1221 1222 if (provider == null) { 1223 String message = "Could not load FunctionProvider class: " + clazz; 1224 context.setRollbackOnly(); 1225 throw new WorkflowException(message); 1226 } 1227 1228 try { 1229 provider.execute(transientVars, args, ps); 1230 } catch (WorkflowException e) { 1231 context.setRollbackOnly(); 1232 throw e; 1233 } 1234 } 1235 } 1236 1237 1241 private boolean transitionWorkflow(WorkflowEntry entry, List currentSteps, WorkflowStore store, WorkflowDescriptor wf, ActionDescriptor action, Map transientVars, Map inputs, PropertySet ps) throws WorkflowException { 1242 Step step = getCurrentStep(wf, action.getId(), currentSteps, transientVars, ps); 1243 1244 Map unmodifiableTransients = Collections.unmodifiableMap(transientVars); 1246 1247 if (action.getValidators().size() > 0) { 1248 verifyInputs(entry, action.getValidators(), unmodifiableTransients, ps); 1249 } 1250 1251 if (step != null) { 1254 List stepPostFunctions = wf.getStep(step.getStepId()).getPostFunctions(); 1255 1256 for (Iterator iterator = stepPostFunctions.iterator(); 1257 iterator.hasNext();) { 1258 FunctionDescriptor function = (FunctionDescriptor) iterator.next(); 1259 executeFunction(function, transientVars, ps); 1260 } 1261 } 1262 1263 List preFunctions = action.getPreFunctions(); 1265 1266 for (Iterator iterator = preFunctions.iterator(); iterator.hasNext();) { 1267 FunctionDescriptor function = (FunctionDescriptor) iterator.next(); 1268 executeFunction(function, transientVars, ps); 1269 } 1270 1271 List conditionalResults = action.getConditionalResults(); 1273 List extraPreFunctions = null; 1274 List extraPostFunctions = null; 1275 ResultDescriptor[] theResults = new ResultDescriptor[1]; 1276 1277 for (Iterator iterator = conditionalResults.iterator(); 1278 iterator.hasNext();) { 1279 ConditionalResultDescriptor conditionalResult = (ConditionalResultDescriptor) iterator.next(); 1280 1281 if (passesConditions(null, conditionalResult.getConditions(), unmodifiableTransients, ps, step.getStepId())) { 1282 theResults[0] = conditionalResult; 1284 1285 if (conditionalResult.getValidators().size() > 0) { 1286 verifyInputs(entry, conditionalResult.getValidators(), unmodifiableTransients, ps); 1287 } 1288 1289 extraPreFunctions = conditionalResult.getPreFunctions(); 1290 extraPostFunctions = conditionalResult.getPostFunctions(); 1291 1292 break; 1293 } 1294 } 1295 1296 if (theResults[0] == null) { 1298 theResults[0] = action.getUnconditionalResult(); 1299 verifyInputs(entry, theResults[0].getValidators(), unmodifiableTransients, ps); 1300 extraPreFunctions = theResults[0].getPreFunctions(); 1301 extraPostFunctions = theResults[0].getPostFunctions(); 1302 } 1303 1304 if (log.isDebugEnabled()) { 1305 log.debug("theResult=" + theResults[0].getStep() + " " + theResults[0].getStatus()); 1306 } 1307 1308 if ((extraPreFunctions != null) && (extraPreFunctions.size() > 0)) { 1309 for (Iterator iterator = extraPreFunctions.iterator(); 1311 iterator.hasNext();) { 1312 FunctionDescriptor function = (FunctionDescriptor) iterator.next(); 1313 executeFunction(function, transientVars, ps); 1314 } 1315 } 1316 1317 if (theResults[0].getSplit() != 0) { 1319 SplitDescriptor splitDesc = wf.getSplit(theResults[0].getSplit()); 1321 Collection results = splitDesc.getResults(); 1322 List splitPreFunctions = new ArrayList(); 1323 List splitPostFunctions = new ArrayList(); 1324 1325 for (Iterator iterator = results.iterator(); iterator.hasNext();) { 1328 ResultDescriptor resultDescriptor = (ResultDescriptor) iterator.next(); 1329 1330 if (resultDescriptor.getValidators().size() > 0) { 1331 verifyInputs(entry, resultDescriptor.getValidators(), unmodifiableTransients, ps); 1332 } 1333 1334 splitPreFunctions.addAll(resultDescriptor.getPreFunctions()); 1335 splitPostFunctions.addAll(resultDescriptor.getPostFunctions()); 1336 } 1337 1338 for (Iterator iterator = splitPreFunctions.iterator(); 1340 iterator.hasNext();) { 1341 FunctionDescriptor function = (FunctionDescriptor) iterator.next(); 1342 executeFunction(function, transientVars, ps); 1343 } 1344 1345 boolean moveFirst = true; 1347 1348 theResults = new ResultDescriptor[results.size()]; 1349 results.toArray(theResults); 1350 1351 for (Iterator iterator = results.iterator(); iterator.hasNext();) { 1352 ResultDescriptor resultDescriptor = (ResultDescriptor) iterator.next(); 1353 Step moveToHistoryStep = null; 1354 1355 if (moveFirst) { 1356 moveToHistoryStep = step; 1357 } 1358 1359 long[] previousIds = null; 1360 1361 if (step != null) { 1362 previousIds = new long[] {step.getId()}; 1363 } 1364 1365 createNewCurrentStep(resultDescriptor, entry, store, action.getId(), moveToHistoryStep, previousIds, transientVars, ps); 1366 moveFirst = false; 1367 } 1368 1369 for (Iterator iterator = splitPostFunctions.iterator(); 1371 iterator.hasNext();) { 1372 FunctionDescriptor function = (FunctionDescriptor) iterator.next(); 1373 executeFunction(function, transientVars, ps); 1374 } 1375 } else if (theResults[0].getJoin() != 0) { 1376 JoinDescriptor joinDesc = wf.getJoin(theResults[0].getJoin()); 1378 step = store.markFinished(step, action.getId(), new Date(), theResults[0].getOldStatus(), context.getCaller()); 1379 store.moveToHistory(step); 1380 1381 Collection joinSteps = new ArrayList(); 1384 joinSteps.add(step); 1385 1386 for (Iterator iterator = currentSteps.iterator(); 1388 iterator.hasNext();) { 1389 Step currentStep = (Step) iterator.next(); 1390 1391 if (currentStep.getId() != step.getId()) { 1392 StepDescriptor stepDesc = wf.getStep(currentStep.getStepId()); 1393 1394 if (stepDesc.resultsInJoin(theResults[0].getJoin())) { 1395 joinSteps.add(currentStep); 1396 } 1397 } 1398 } 1399 1400 List historySteps = store.findHistorySteps(entry.getId()); 1403 1404 for (Iterator i = historySteps.iterator(); i.hasNext();) { 1405 Step historyStep = (Step) i.next(); 1406 1407 if (historyStep.getId() != step.getId()) { 1408 StepDescriptor stepDesc = wf.getStep(historyStep.getStepId()); 1409 1410 if (stepDesc.resultsInJoin(theResults[0].getJoin())) { 1411 joinSteps.add(historyStep); 1412 } 1413 } 1414 } 1415 1416 JoinNodes jn = new JoinNodes(joinSteps); 1417 transientVars.put("jn", jn); 1418 1419 if (passesConditions(null, joinDesc.getConditions(), unmodifiableTransients, ps, 0)) { 1421 ResultDescriptor joinresult = joinDesc.getResult(); 1423 1424 if (joinresult.getValidators().size() > 0) { 1425 verifyInputs(entry, joinresult.getValidators(), unmodifiableTransients, ps); 1426 } 1427 1428 for (Iterator iterator = joinresult.getPreFunctions().iterator(); 1430 iterator.hasNext();) { 1431 FunctionDescriptor function = (FunctionDescriptor) iterator.next(); 1432 executeFunction(function, transientVars, ps); 1433 } 1434 1435 long[] previousIds = new long[joinSteps.size()]; 1436 int i = 1; 1437 1438 for (Iterator iterator = joinSteps.iterator(); 1439 iterator.hasNext();) { 1440 Step currentStep = (Step) iterator.next(); 1441 1442 if (currentStep.getId() != step.getId()) { 1443 if (!historySteps.contains(currentStep)) { 1446 store.moveToHistory(currentStep); 1447 } 1448 1449 previousIds[i] = currentStep.getId(); 1450 i++; 1451 } 1452 } 1453 1454 previousIds[0] = step.getId(); 1456 theResults[0] = joinDesc.getResult(); 1457 1458 createNewCurrentStep(joinDesc.getResult(), entry, store, action.getId(), null, previousIds, transientVars, ps); 1460 1461 for (Iterator iterator = joinresult.getPostFunctions().iterator(); 1463 iterator.hasNext();) { 1464 FunctionDescriptor function = (FunctionDescriptor) iterator.next(); 1465 executeFunction(function, transientVars, ps); 1466 } 1467 } 1468 } else { 1469 long[] previousIds = null; 1471 1472 if (step != null) { 1473 previousIds = new long[] {step.getId()}; 1474 } 1475 1476 createNewCurrentStep(theResults[0], entry, store, action.getId(), step, previousIds, transientVars, ps); 1477 } 1478 1479 if (extraPostFunctions != null) { 1481 for (Iterator iterator = extraPostFunctions.iterator(); 1482 iterator.hasNext();) { 1483 FunctionDescriptor function = (FunctionDescriptor) iterator.next(); 1484 executeFunction(function, transientVars, ps); 1485 } 1486 } 1487 1488 List postFunctions = action.getPostFunctions(); 1489 1490 for (Iterator iterator = postFunctions.iterator(); iterator.hasNext();) { 1491 FunctionDescriptor function = (FunctionDescriptor) iterator.next(); 1492 executeFunction(function, transientVars, ps); 1493 } 1494 1495 if ((wf.getInitialAction(action.getId()) != null) && (entry.getState() != WorkflowEntry.ACTIVATED)) { 1497 changeEntryState(entry.getId(), WorkflowEntry.ACTIVATED); 1498 } 1499 1500 if (action.isFinish()) { 1502 completeEntry(entry.getId(), getCurrentSteps(entry.getId())); 1503 1504 return true; 1505 } 1506 1507 int[] availableAutoActions = getAvailableAutoActions(entry.getId(), inputs); 1509 1510 for (int j = 0; j < availableAutoActions.length; j++) { 1511 int actionId = availableAutoActions[j]; 1512 doAction(entry.getId(), actionId, inputs); 1513 1514 break; 1515 } 1516 1517 return false; 1518 } 1519} 1520 | Popular Tags |