001/* 002 * (C) Copyright 2012 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Florent Guillaume 018 */ 019package org.nuxeo.ecm.platform.routing.core.impl; 020 021import java.io.Serializable; 022import java.util.ArrayList; 023import java.util.Calendar; 024import java.util.Date; 025import java.util.List; 026import java.util.Map; 027 028import org.apache.commons.lang.BooleanUtils; 029import org.apache.commons.lang.builder.ToStringBuilder; 030import org.nuxeo.ecm.core.api.CoreSession; 031import org.nuxeo.ecm.core.api.DocumentModel; 032import org.nuxeo.ecm.core.api.model.Property; 033import org.nuxeo.ecm.core.api.model.impl.ListProperty; 034import org.nuxeo.ecm.core.api.model.impl.MapProperty; 035import org.nuxeo.ecm.platform.routing.api.DocumentRoute; 036import org.nuxeo.ecm.platform.routing.api.exception.DocumentRouteException; 037 038/** 039 * A node for a route graph. Represents operation chains, associated task and form, output transitions and their 040 * conditions, etc. 041 * 042 * @since 5.6 043 */ 044public interface GraphNode { 045 046 String MERGE_ONE = "one"; 047 048 String MERGE_ALL = "all"; 049 050 String PROP_NODE_ID = "rnode:nodeId"; 051 052 String PROP_TITLE = "dc:title"; 053 054 String PROP_START = "rnode:start"; 055 056 String PROP_STOP = "rnode:stop"; 057 058 String PROP_MERGE = "rnode:merge"; 059 060 String PROP_COUNT = "rnode:count"; 061 062 String PROP_CANCELED = "rnode:canceled"; 063 064 String PROP_INPUT_CHAIN = "rnode:inputChain"; 065 066 String PROP_OUTPUT_CHAIN = "rnode:outputChain"; 067 068 String PROP_HAS_TASK = "rnode:hasTask"; 069 070 String PROP_VARIABLES_FACET = "rnode:variablesFacet"; 071 072 String PROP_TRANSITIONS = "rnode:transitions"; 073 074 String PROP_TRANS_NAME = "name"; 075 076 String PROP_TRANS_TARGET = "targetId"; 077 078 String PROP_TRANS_CONDITION = "condition"; 079 080 String PROP_TRANS_RESULT = "result"; 081 082 String PROP_TRANS_CHAIN = "chain"; 083 084 String PROP_TRANS_LABEL = "label"; 085 086 /** 087 * @since 7.1 a transition can hold a custom path 088 */ 089 String PROP_TRANS_PATH = "path"; 090 091 String PROP_TASK_ASSIGNEES = "rnode:taskAssignees"; 092 093 String PROP_TASK_ASSIGNEES_VAR = "rnode:taskAssigneesExpr"; 094 095 String PROP_TASK_ASSIGNEES_PERMISSION = "rnode:taskAssigneesPermission"; 096 097 String PROP_TASK_DUE_DATE = "rnode:taskDueDate"; 098 099 String PROP_TASK_DIRECTIVE = "rnode:taskDirective"; 100 101 String PROP_TASK_LAYOUT = "rnode:taskLayout"; 102 103 String PROP_TASK_BUTTONS = "rnode:taskButtons"; 104 105 String PROP_BTN_NAME = "name"; 106 107 String PROP_BTN_LABEL = "label"; 108 109 String PROP_BTN_FILTER = "filter"; 110 111 String PROP_NODE_X_COORDINATE = "rnode:taskX"; 112 113 String PROP_NODE_Y_COORDINATE = "rnode:taskY"; 114 115 /** 116 * @since 5.7.3 a node can create multiple tasks, in this case, this stores the status of the last task ended 117 */ 118 String PROP_NODE_BUTTON = "rnode:button"; 119 120 String PROP_NODE_START_DATE = "rnode:startDate"; 121 122 String PROP_NODE_END_DATE = "rnode:endDate"; 123 124 String PROP_NODE_LAST_ACTOR = "rnode:lastActor"; 125 126 String PROP_TASK_DOC_TYPE = "rnode:taskDocType"; 127 128 String PROP_TASK_NOTIFICATION_TEMPLATE = "rnode:taskNotificationTemplate"; 129 130 String PROP_TASK_DUE_DATE_EXPR = "rnode:taskDueDateExpr"; 131 132 /** @since 5.7.2 */ 133 String PROP_EXECUTE_ONLY_FIRST_TRANSITION = "rnode:executeOnlyFirstTransition"; 134 135 /** 136 * The sub-route model id (expression) to run, if present. 137 * 138 * @since 5.7.2 139 */ 140 String PROP_SUB_ROUTE_MODEL_EXPR = "rnode:subRouteModelExpr"; 141 142 /** 143 * The sub-route instance id being run while this node is suspended. 144 * 145 * @since 5.7.2 146 */ 147 String PROP_SUB_ROUTE_INSTANCE_ID = "rnode:subRouteInstanceId"; 148 149 /** 150 * The sub-route variables to set (key/value list). 151 * 152 * @since 5.7.2 153 */ 154 String PROP_SUB_ROUTE_VARS = "rnode:subRouteVariables"; 155 156 /** @since 5.7.2 */ 157 String PROP_KEYVALUE_KEY = "key"; 158 159 /** @since 5.7.2 */ 160 String PROP_KEYVALUE_VALUE = "value"; 161 162 // @since 5.7.2 163 String PROP_ESCALATION_RULES = "rnode:escalationRules"; 164 165 // @since 5.7.2 166 String PROP_ESCALATION_RULE_ID = "name"; 167 168 // @since 5.7.2 169 String PROP_ESCALATION_RULE_LABEL = "label"; 170 171 // @since 5.7.2 172 String PROP_ESCALATION_RULE_MULTIPLE_EXECUTION = "multipleExecution"; 173 174 // @since 5.7.2 175 String PROP_ESCALATION_RULE_CONDITION = "condition"; 176 177 // @since 5.7.2 178 String PROP_ESCALATION_RULE_CHAIN = "chain"; 179 180 // @since 5.7.2 181 String PROP_ESCALATION_RULE_EXECUTED = "executed"; 182 183 // @since 5.9.3 184 String PROP_LAST_EXECUTION_TIME = "executionDate"; 185 186 // @since 5.7.3 187 String PROP_HAS_MULTIPLE_TASKS = "rnode:hasMultipleTasks"; 188 189 // @since 5.7.3 190 String PROP_TASKS_INFO = "rnode:tasksInfo"; 191 192 // @since 5.7.3 193 String PROP_TASK_INFO_ACTOR = "actor"; 194 195 // @since 5.7.3 196 String PROP_TASK_INFO_COMMENT = "comment"; 197 198 // @since 5.7.3 199 String PROP_TASK_INFO_STATUS = "status"; 200 201 // @since 5.7.3 202 String PROP_TASK_INFO_ENDED = "ended"; 203 204 // @since 5.7.3 205 String PROP_TASK_INFO_TASK_DOC_ID = "taskDocId"; 206 207 // @since 5.7.3 208 String PROP_ALLOW_TASK_REASSIGNMENT = "rnode:allowTaskReassignment"; 209 210 // @since 5.6 211 // if present as the node variable, acts as a built-in variable: 212 // is passed to the task comment and logged in by audit; 213 // internally rested when set on node having multiple tasks. 214 String NODE_VARIABLE_COMMENT = "comment"; 215 216 /** 217 * The internal state of a node. 218 */ 219 enum State { 220 /** Node is ready. */ 221 READY("ready", "toReady"), 222 /** Merge node is waiting for more incoming transitions. */ 223 WAITING("waiting", "toWaiting"), 224 /** While executing input phase. Not persisted. */ 225 RUNNING_INPUT, 226 /** Task node is waiting for task to be done. */ 227 SUSPENDED("suspended", "toSuspended"), 228 /** While executing output phase. Not persisted. */ 229 RUNNING_OUTPUT; 230 231 private final String lifeCycleState; 232 233 private final String transition; 234 235 private State() { 236 lifeCycleState = null; 237 transition = null; 238 } 239 240 private State(String lifeCycleState, String transition) { 241 this.lifeCycleState = lifeCycleState; 242 this.transition = transition; 243 } 244 245 /** 246 * Corresponding lifecycle state. 247 */ 248 public String getLifeCycleState() { 249 return lifeCycleState; 250 } 251 252 /** 253 * Transition leading to this state. 254 */ 255 public String getTransition() { 256 return transition; 257 } 258 259 public static State fromString(String s) { 260 try { 261 return State.valueOf(s.toUpperCase()); 262 } catch (IllegalArgumentException e) { 263 throw new IllegalArgumentException(s); 264 } 265 } 266 } 267 268 /** 269 * @since 7.1 270 */ 271 class Point { 272 273 public double x; 274 275 public double y; 276 277 public Point(double x, double y) { 278 this.x = x; 279 this.y = y; 280 } 281 } 282 283 class Transition implements Comparable<Transition>, Serializable { 284 285 public GraphNode source; 286 287 public MapProperty prop; 288 289 public String id; 290 291 public String condition; 292 293 public String chain; 294 295 public String target; 296 297 public String label; 298 299 public boolean result; 300 301 /** 302 * @since 7.1 303 */ 304 public List<Point> path; 305 306 /** Computed by graph. */ 307 public boolean loop; 308 309 protected Transition(GraphNode source, Property p) { 310 this.source = source; 311 prop = (MapProperty) p; 312 id = (String) prop.get(PROP_TRANS_NAME).getValue(); 313 condition = (String) prop.get(PROP_TRANS_CONDITION).getValue(); 314 chain = (String) prop.get(PROP_TRANS_CHAIN).getValue(); 315 target = (String) prop.get(PROP_TRANS_TARGET).getValue(); 316 label = (String) prop.get(PROP_TRANS_LABEL).getValue(); 317 Property resultProp = prop.get(PROP_TRANS_RESULT); 318 if (resultProp != null) { 319 result = BooleanUtils.isTrue(resultProp.getValue(Boolean.class)); 320 } 321 } 322 323 protected void setResult(boolean bool) { 324 result = bool; 325 prop.get(PROP_TRANS_RESULT).setValue(Boolean.valueOf(bool)); 326 } 327 328 @Override 329 public int compareTo(Transition other) { 330 return id.compareTo(other.id); 331 } 332 333 @Override 334 public String toString() { 335 return new ToStringBuilder(this).append("id", id).append("condition", condition).append("result", result).toString(); 336 } 337 338 public String getTarget() { 339 return target; 340 } 341 342 public String getId() { 343 return id; 344 } 345 346 public String getLabel() { 347 return label; 348 } 349 350 /** 351 * @since 7.1 352 */ 353 public List<Point> getPath() { 354 if (path == null) { 355 path = computePath(); 356 } 357 return path; 358 } 359 360 protected List<Point> computePath() { 361 ListProperty props = (ListProperty) prop.get(PROP_TRANS_PATH); 362 List<Point> points = new ArrayList<>(props.size()); 363 for (Property p : props) { 364 points.add(new Point( 365 (Double) p.get("x").getValue(), 366 (Double) p.get("y").getValue())); 367 } 368 return points; 369 } 370 } 371 372 public class Button implements Comparable<Button> { 373 374 public GraphNode source; 375 376 public String name; 377 378 public String label; 379 380 public String filter; 381 382 public MapProperty prop; 383 384 public Button(GraphNode source, Property p) { 385 this.source = source; 386 this.prop = (MapProperty) p; 387 name = (String) prop.get(PROP_BTN_NAME).getValue(); 388 label = (String) prop.get(PROP_BTN_LABEL).getValue(); 389 filter = (String) prop.get(PROP_BTN_FILTER).getValue(); 390 } 391 392 @Override 393 public int compareTo(Button other) { 394 return name.compareTo(other.name); 395 } 396 397 public String getLabel() { 398 return label; 399 } 400 401 public String getName() { 402 return name; 403 } 404 405 public String getFilter() { 406 return filter; 407 } 408 } 409 410 /** 411 * @since 5.7.2 412 */ 413 class EscalationRule implements Comparable<EscalationRule> { 414 415 protected String id; 416 417 protected String label; 418 419 protected boolean multipleExecution; 420 421 protected String condition; 422 423 protected boolean executed; 424 425 protected String chain; 426 427 protected MapProperty prop; 428 429 protected GraphNode node; 430 431 /** 432 * @since 5.9.3 433 */ 434 protected Calendar lastExcutionTime; 435 436 public EscalationRule(GraphNode node, Property p) { 437 this.prop = (MapProperty) p; 438 this.node = node; 439 this.id = (String) p.get(PROP_ESCALATION_RULE_ID).getValue(); 440 this.label = (String) p.get(PROP_ESCALATION_RULE_LABEL).getValue(); 441 Property multipleEvaluationProp = prop.get(PROP_ESCALATION_RULE_MULTIPLE_EXECUTION); 442 if (multipleEvaluationProp != null) { 443 multipleExecution = BooleanUtils.isTrue(multipleEvaluationProp.getValue(Boolean.class)); 444 } 445 this.condition = (String) p.get(PROP_ESCALATION_RULE_CONDITION).getValue(); 446 Property evaluatedProp = prop.get(PROP_ESCALATION_RULE_EXECUTED); 447 if (evaluatedProp != null) { 448 executed = BooleanUtils.isTrue(evaluatedProp.getValue(Boolean.class)); 449 } 450 this.chain = (String) p.get(PROP_ESCALATION_RULE_CHAIN).getValue(); 451 this.lastExcutionTime = (Calendar) p.get(PROP_LAST_EXECUTION_TIME).getValue(); 452 } 453 454 @Override 455 public int compareTo(EscalationRule o) { 456 return id.compareTo(o.id); 457 } 458 459 public String getLabel() { 460 return label; 461 } 462 463 public String getChain() { 464 return chain; 465 } 466 467 public GraphNode getNode() { 468 return node; 469 } 470 471 public void setExecuted(boolean executed) { 472 this.executed = executed; 473 prop.get(PROP_ESCALATION_RULE_EXECUTED).setValue(Boolean.valueOf(executed)); 474 if (executed) { 475 setExecutionTime(Calendar.getInstance()); 476 } 477 } 478 479 protected void setExecutionTime(Calendar time) { 480 prop.get(PROP_LAST_EXECUTION_TIME).setValue(time); 481 this.lastExcutionTime = time; 482 } 483 484 public boolean isExecuted() { 485 return executed; 486 } 487 488 public String getId() { 489 return id; 490 } 491 492 public boolean isMultipleExecution() { 493 return multipleExecution; 494 } 495 496 /** 497 * @since 5.9.3 Returns 'null' if the node was not executed, or the executed date was not computed ( for rules 498 * created before 499 * @5.9.3) 500 */ 501 public Calendar getLastExecutionTime() { 502 if (executed && lastExcutionTime != null) { 503 return lastExcutionTime; 504 } 505 return null; 506 } 507 } 508 509 /** 510 * @since 5.7.3 511 */ 512 class TaskInfo implements Comparable<TaskInfo>, Serializable { 513 514 protected String taskDocId; 515 516 protected String actor; 517 518 protected String comment; 519 520 protected String status; 521 522 protected boolean ended; 523 524 protected MapProperty prop; 525 526 protected GraphNode node; 527 528 public TaskInfo(GraphNode node, Property p) { 529 this.prop = (MapProperty) p; 530 this.node = node; 531 this.taskDocId = (String) p.get(PROP_TASK_INFO_TASK_DOC_ID).getValue(); 532 this.status = (String) p.get(PROP_TASK_INFO_STATUS).getValue(); 533 this.actor = (String) p.get(PROP_TASK_INFO_ACTOR).getValue(); 534 this.comment = (String) p.get(PROP_TASK_INFO_COMMENT).getValue(); 535 Property ended = prop.get(PROP_TASK_INFO_ENDED); 536 if (ended != null) { 537 this.ended = BooleanUtils.isTrue(ended.getValue(Boolean.class)); 538 } 539 } 540 541 public TaskInfo(GraphNode node, String taskDocId) { 542 this.node = node; 543 this.prop = (MapProperty) ((ListProperty) node.getDocument().getProperty(PROP_TASKS_INFO)).addEmpty(); 544 this.prop.get(PROP_TASK_INFO_TASK_DOC_ID).setValue(taskDocId); 545 this.taskDocId = taskDocId; 546 } 547 548 @Override 549 public int compareTo(TaskInfo o) { 550 return taskDocId.compareTo(o.taskDocId); 551 } 552 553 public String getTaskDocId() { 554 return taskDocId; 555 } 556 557 public String getActor() { 558 return actor; 559 } 560 561 public String getComment() { 562 return comment; 563 } 564 565 public String getStatus() { 566 return status; 567 } 568 569 public GraphNode getNode() { 570 return node; 571 } 572 573 public boolean isEnded() { 574 return ended; 575 } 576 577 public void setComment(String comment) { 578 this.comment = comment; 579 prop.get(PROP_TASK_INFO_COMMENT).setValue(comment); 580 } 581 582 public void setStatus(String status) { 583 this.status = status; 584 prop.get(PROP_TASK_INFO_STATUS).setValue(status); 585 586 } 587 588 public void setActor(String actor) { 589 this.actor = actor; 590 prop.get(PROP_TASK_INFO_ACTOR).setValue(actor); 591 } 592 593 public void setEnded(boolean ended) { 594 this.ended = ended; 595 prop.get(PROP_TASK_INFO_ENDED).setValue(Boolean.valueOf(ended)); 596 } 597 } 598 599 /** 600 * Get the node id. 601 * 602 * @return the node id 603 */ 604 String getId(); 605 606 /** 607 * Get the node state. 608 * 609 * @return the node state 610 */ 611 State getState(); 612 613 /** 614 * Set the node state. 615 * 616 * @param state the node state 617 */ 618 void setState(State state); 619 620 /** 621 * Checks if this is the start node. 622 */ 623 boolean isStart(); 624 625 /** 626 * Checks if this is a stop node. 627 */ 628 boolean isStop(); 629 630 /** 631 * Checks if this is a merge node. 632 */ 633 boolean isMerge(); 634 635 /** 636 * Checks if the merge is ready to execute (enough input transitions are present). 637 */ 638 boolean canMerge(); 639 640 /** 641 * Notes that this node was canceled (increments canceled counter). 642 */ 643 void setCanceled(); 644 645 /** 646 * Gets the canceled count for this node. 647 * 648 * @return 649 */ 650 long getCanceledCount(); 651 652 /** 653 * Cancels the tasks not ended on this node. 654 */ 655 void cancelTasks(); 656 657 /** 658 * Get input chain. 659 * 660 * @return the input chain 661 */ 662 String getInputChain(); 663 664 /** 665 * Get output chain. 666 * 667 * @return the output chain 668 */ 669 String getOutputChain(); 670 671 /** 672 * Checks it this node has an associated user task. 673 */ 674 boolean hasTask(); 675 676 /** 677 * Gets the task assignees 678 * 679 * @return the task assignees 680 */ 681 List<String> getTaskAssignees(); 682 683 /** 684 * Gets the due date 685 * 686 * @return 687 */ 688 Date getTaskDueDate(); 689 690 /** 691 * Gets the task directive 692 * 693 * @return 694 */ 695 String getTaskDirective(); 696 697 /** 698 * Gets the permission to the granted to the actors on this task on the document following the workflow 699 * 700 * @return 701 */ 702 String getTaskAssigneesPermission(); 703 704 /** 705 * Gets the task layout 706 * 707 * @return 708 */ 709 String getTaskLayout(); 710 711 /** 712 * @returns the taskDocType. If none is specified, the default task type is returned. 713 */ 714 String getTaskDocType(); 715 716 String getTaskNotificationTemplate(); 717 718 /** 719 * Does bookkeeping at node start. 720 */ 721 void starting(); 722 723 /** 724 * Does bookkeeping at node end. 725 */ 726 void ending(); 727 728 /** 729 * Executes an Automation chain in the context of this node. 730 * 731 * @param chainId the chain 732 */ 733 void executeChain(String chainId) throws DocumentRouteException; 734 735 /** Internal during graph init. */ 736 void initAddInputTransition(Transition transition); 737 738 /** 739 * Gets the input transitions. 740 */ 741 List<Transition> getInputTransitions(); 742 743 /** 744 * Gets the output transitions. 745 */ 746 List<Transition> getOutputTransitions(); 747 748 String getTaskDueDateExpr(); 749 750 /** 751 * Executes an Automation chain in the context of this node for a given transition 752 * 753 * @param transition the transition 754 */ 755 void executeTransitionChain(Transition transition) throws DocumentRouteException; 756 757 /** 758 * Evaluates transition conditions and returns the transitions that were true. 759 * <p> 760 * Transitions are evaluated in the order set on the node when the workflow was designed. Since @5.7.2 if the node 761 * has the property "executeOnlyFirstTransition" set to true, only the first transition evaluated to true is 762 * returned 763 * 764 * @return the true transitions 765 */ 766 List<Transition> evaluateTransitions() throws DocumentRouteException; 767 768 /** 769 * Sets the graph and node variables. 770 * 771 * @param map the map of variables 772 */ 773 void setAllVariables(Map<String, Object> map); 774 775 /** 776 * Sets the graph and node variables. 777 * 778 * @param map the map of variables 779 * @param allowGlobalVariablesAssignement if set to false, throw a DocumentRouteException when trying to set global 780 * variables when not supposed to 781 * @since 7.2 782 */ 783 void setAllVariables(Map<String, Object> map, final boolean allowGlobalVariablesAssignement); 784 785 /** 786 * Gets the task buttons 787 */ 788 List<Button> getTaskButtons(); 789 790 /** 791 * Has the node the given action. 792 * 793 * @since 7.2 794 */ 795 boolean hasTaskButton(final String name); 796 797 /** 798 * Gets the document representing this node 799 * 800 * @return 801 */ 802 DocumentModel getDocument(); 803 804 /** 805 * Gets a map containing the variables currently defined on this node 806 * 807 * @return 808 */ 809 Map<String, Serializable> getVariables(); 810 811 /** 812 * Gets a map containing the Json formatted variables currently defined on this node 813 * 814 * @return 815 * @since 7.2 816 */ 817 Map<String, Serializable> getJsonVariables(); 818 819 /** 820 * Sets the property button on the node, keeping the id of the last action executed by the user on the associated 821 * task if any 822 * 823 * @param status 824 */ 825 void setButton(String status); 826 827 /** 828 * Sets the last actor on a node (user who completed the task). 829 * 830 * @param actor the user id 831 */ 832 void setLastActor(String actor); 833 834 /** 835 * Evaluates the task assignees from the taskAssigneesVar 836 * <p> 837 * 838 * @return 839 */ 840 List<String> evaluateTaskAssignees() throws DocumentRouteException; 841 842 /** 843 * Evaluates the task due date from the taskDueDateExpr and sets it as the dueDate 844 * 845 * @return 846 * @throws DocumentRouteException 847 */ 848 Date computeTaskDueDate() throws DocumentRouteException; 849 850 /** 851 * Gets a map containing the workflow and node variables and workflow documents. 852 * 853 * @param detached The documents added into this map can be detached or not 854 */ 855 Map<String, Serializable> getWorkflowContextualInfo(CoreSession session, boolean detached); 856 857 /** 858 * When workflow engine runs an exclusive node, it evaluates the transition one by one and stops a soon as one of 859 * the transition is evaluated to true 860 * 861 * @since 5.7.2 862 */ 863 boolean executeOnlyFirstTransition(); 864 865 /** 866 * Checks if this node has a sub-route model defined. 867 * 868 * @return {@code true} if there is a sub-route 869 * @since 5.7.2 870 */ 871 boolean hasSubRoute() throws DocumentRouteException; 872 873 /** 874 * Gets the sub-route model id. 875 * <p> 876 * If this is present, then this node will be suspended while the sub-route is run. When the sub-route ends, this 877 * node will resume. 878 * 879 * @return the sub-route id, or {@code null} if none is defined 880 * @since 5.7.2 881 */ 882 String getSubRouteModelId() throws DocumentRouteException; 883 884 /** 885 * Starts the sub-route on this node. 886 * 887 * @return the sub-route 888 * @since 5.7.2 889 */ 890 DocumentRoute startSubRoute() throws DocumentRouteException; 891 892 /** 893 * Cancels the sub-route if there is one. 894 * 895 * @since 5.7.2 896 */ 897 void cancelSubRoute() throws DocumentRouteException; 898 899 /** 900 * Evaluates the rules for the escalation rules and returns the ones to be executed. The rules already executed and 901 * not having the property multipleExecution = true are also ignored 902 * 903 * @since 5.7.2 904 */ 905 List<EscalationRule> evaluateEscalationRules(); 906 907 /** 908 * Gets the list of all escalation rules for the node 909 * 910 * @since 5.7.2 911 */ 912 List<EscalationRule> getEscalationRules(); 913 914 /** 915 * Checks if this node has created multiple tasks, one for each assignees. 916 * 917 * @since 5.7.3 918 */ 919 boolean hasMultipleTasks(); 920 921 /** 922 * Gets all the tasks info for the tasks created from this node 923 * 924 * @since 5.7.3 925 */ 926 List<TaskInfo> getTasksInfo(); 927 928 /** 929 * Persist the info when a new task is created from this node 930 * 931 * @since 5.7.3 932 */ 933 void addTaskInfo(String taskId); 934 935 /** 936 * Persist these info from the task on the node. Status is the id of the button clicked to end the task by the 937 * actor. 938 * 939 * @since 5.7.3 940 */ 941 void updateTaskInfo(String taskId, boolean ended, String status, String actor, String comment); 942 943 /** 944 * Gets all the ended tasks originating from this node. This also counts the canceled tasks. 945 * 946 * @since 5.7.3 947 */ 948 List<TaskInfo> getEndedTasksInfo(); 949 950 /** 951 * Gets all the ended tasks originating from this node that were processed with a status. Doesn't count the canceled 952 * tasks. 953 * 954 * @since 5.7.3 955 */ 956 List<TaskInfo> getProcessedTasksInfo(); 957 958 /** 959 * Returns false if all tasks created from this node were ended. 960 * 961 * @since 5.7.3 962 */ 963 boolean hasOpenTasks(); 964 965 /** 966 * Returns true if tasks created from this node can be reassigned. 967 * 968 * @since 5.7.3 969 */ 970 boolean allowTaskReassignment(); 971 972 /** 973 * Sets the variable on this node if it exists as a Node Variable. 974 * 975 * @since 5.8 976 */ 977 public void setVariable(String name, String value); 978 979 /** 980 * Sets the node variables. 981 * 982 * @since 5.9.3, 5.8.0-HF11 983 * @param map the map of variables 984 */ 985 void setVariables(Map<String, Serializable> map); 986 987 /** 988 * Sets the variables of the workflow based on their JSON representation (especially for scalar lists). Eg. 989 * Map<String, String> map = new HashMap<String, String>(); 990 * map.put("contributors","[\"John Doe\", \"John Smith\"]"); map.put("title","Test Title"); 991 * 992 * @param map the map of variables 993 * @since 5.9.3, 5.8.0-HF11 994 */ 995 void setJSONVariables(Map<String, String> map); 996 997 /** 998 * @since 7.4 999 */ 1000 void removeTaskInfo(String taskId); 1001 1002}