001/* 002 * (C) Copyright 2012-2018 Nuxeo (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.lang3.BooleanUtils; 029import org.apache.commons.lang3.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 5.9.3) 499 */ 500 public Calendar getLastExecutionTime() { 501 if (executed && lastExcutionTime != null) { 502 return lastExcutionTime; 503 } 504 return null; 505 } 506 } 507 508 /** 509 * @since 5.7.3 510 */ 511 class TaskInfo implements Comparable<TaskInfo>, Serializable { 512 513 protected String taskDocId; 514 515 protected String actor; 516 517 protected String comment; 518 519 protected String status; 520 521 protected boolean ended; 522 523 protected MapProperty prop; 524 525 protected GraphNode node; 526 527 public TaskInfo(GraphNode node, Property p) { 528 this.prop = (MapProperty) p; 529 this.node = node; 530 this.taskDocId = (String) p.get(PROP_TASK_INFO_TASK_DOC_ID).getValue(); 531 this.status = (String) p.get(PROP_TASK_INFO_STATUS).getValue(); 532 this.actor = (String) p.get(PROP_TASK_INFO_ACTOR).getValue(); 533 this.comment = (String) p.get(PROP_TASK_INFO_COMMENT).getValue(); 534 Property ended = prop.get(PROP_TASK_INFO_ENDED); 535 if (ended != null) { 536 this.ended = BooleanUtils.isTrue(ended.getValue(Boolean.class)); 537 } 538 } 539 540 public TaskInfo(GraphNode node, String taskDocId) { 541 this.node = node; 542 this.prop = (MapProperty) ((ListProperty) node.getDocument().getProperty(PROP_TASKS_INFO)).addEmpty(); 543 this.prop.get(PROP_TASK_INFO_TASK_DOC_ID).setValue(taskDocId); 544 this.taskDocId = taskDocId; 545 } 546 547 @Override 548 public int compareTo(TaskInfo o) { 549 return taskDocId.compareTo(o.taskDocId); 550 } 551 552 public String getTaskDocId() { 553 return taskDocId; 554 } 555 556 public String getActor() { 557 return actor; 558 } 559 560 public String getComment() { 561 return comment; 562 } 563 564 public String getStatus() { 565 return status; 566 } 567 568 public GraphNode getNode() { 569 return node; 570 } 571 572 public boolean isEnded() { 573 return ended; 574 } 575 576 public void setComment(String comment) { 577 this.comment = comment; 578 prop.get(PROP_TASK_INFO_COMMENT).setValue(comment); 579 } 580 581 public void setStatus(String status) { 582 this.status = status; 583 prop.get(PROP_TASK_INFO_STATUS).setValue(status); 584 585 } 586 587 public void setActor(String actor) { 588 this.actor = actor; 589 prop.get(PROP_TASK_INFO_ACTOR).setValue(actor); 590 } 591 592 public void setEnded(boolean ended) { 593 this.ended = ended; 594 prop.get(PROP_TASK_INFO_ENDED).setValue(Boolean.valueOf(ended)); 595 } 596 } 597 598 /** 599 * Get the node id. 600 * 601 * @return the node id 602 */ 603 String getId(); 604 605 /** 606 * Get the node state. 607 * 608 * @return the node state 609 */ 610 State getState(); 611 612 /** 613 * Set the node state. 614 * 615 * @param state the node state 616 */ 617 void setState(State state); 618 619 /** 620 * Checks if this is the start node. 621 */ 622 boolean isStart(); 623 624 /** 625 * Checks if this is a stop node. 626 */ 627 boolean isStop(); 628 629 /** 630 * Checks if this is a merge node. 631 */ 632 boolean isMerge(); 633 634 /** 635 * Checks if the merge is ready to execute (enough input transitions are present). 636 */ 637 boolean canMerge(); 638 639 /** 640 * Notes that this node was canceled (increments canceled counter). 641 */ 642 void setCanceled(); 643 644 /** 645 * Gets the canceled count for this node. 646 */ 647 long getCanceledCount(); 648 649 /** 650 * Cancels the tasks not ended on this node. 651 */ 652 void cancelTasks(); 653 654 /** 655 * Get input chain. 656 * 657 * @return the input chain 658 */ 659 String getInputChain(); 660 661 /** 662 * Get output chain. 663 * 664 * @return the output chain 665 */ 666 String getOutputChain(); 667 668 /** 669 * Checks it this node has an associated user task. 670 */ 671 boolean hasTask(); 672 673 /** 674 * Gets the task assignees 675 * 676 * @return the task assignees 677 */ 678 List<String> getTaskAssignees(); 679 680 /** 681 * Gets the due date 682 */ 683 Date getTaskDueDate(); 684 685 /** 686 * Gets the task directive 687 */ 688 String getTaskDirective(); 689 690 /** 691 * Gets the permission to the granted to the actors on this task on the document following the workflow 692 */ 693 String getTaskAssigneesPermission(); 694 695 /** 696 * Gets the task layout 697 */ 698 String getTaskLayout(); 699 700 /** 701 * @return the taskDocType. If none is specified, the default task type is returned. 702 */ 703 String getTaskDocType(); 704 705 String getTaskNotificationTemplate(); 706 707 /** 708 * Does bookkeeping at node start. 709 */ 710 void starting(); 711 712 /** 713 * Does bookkeeping at node end. 714 */ 715 void ending(); 716 717 /** 718 * Executes an Automation chain in the context of this node. 719 * 720 * @param chainId the chain 721 */ 722 void executeChain(String chainId) throws DocumentRouteException; 723 724 /** Internal during graph init. */ 725 void initAddInputTransition(Transition transition); 726 727 /** 728 * Gets the input transitions. 729 */ 730 List<Transition> getInputTransitions(); 731 732 /** 733 * Gets the output transitions. 734 */ 735 List<Transition> getOutputTransitions(); 736 737 String getTaskDueDateExpr(); 738 739 /** 740 * Executes an Automation chain in the context of this node for a given transition 741 * 742 * @param transition the transition 743 */ 744 void executeTransitionChain(Transition transition) throws DocumentRouteException; 745 746 /** 747 * Evaluates transition conditions and returns the transitions that were true. 748 * <p> 749 * Transitions are evaluated in the order set on the node when the workflow was designed. Since @5.7.2 if the node 750 * has the property "executeOnlyFirstTransition" set to true, only the first transition evaluated to true is 751 * returned 752 * 753 * @return the true transitions 754 */ 755 List<Transition> evaluateTransitions() throws DocumentRouteException; 756 757 /** 758 * Sets the graph and node variables. 759 * 760 * @param map the map of variables 761 */ 762 void setAllVariables(Map<String, Object> map); 763 764 /** 765 * Sets the graph and node variables. 766 * 767 * @param map the map of variables 768 * @param allowGlobalVariablesAssignement if set to false, throw a DocumentRouteException when trying to set global 769 * variables when not supposed to 770 * @since 7.2 771 */ 772 void setAllVariables(Map<String, Object> map, final boolean allowGlobalVariablesAssignement); 773 774 /** 775 * Gets the task buttons 776 */ 777 List<Button> getTaskButtons(); 778 779 /** 780 * Has the node the given action. 781 * 782 * @since 7.2 783 */ 784 boolean hasTaskButton(final String name); 785 786 /** 787 * Gets the document representing this node 788 */ 789 DocumentModel getDocument(); 790 791 /** 792 * Gets a map containing the variables currently defined on this node 793 */ 794 Map<String, Serializable> getVariables(); 795 796 /** 797 * Gets a map containing the Json formatted variables currently defined on this node 798 * @since 7.2 799 */ 800 Map<String, Serializable> getJsonVariables(); 801 802 /** 803 * Sets the property button on the node, keeping the id of the last action executed by the user on the associated 804 * task if any 805 */ 806 void setButton(String status); 807 808 /** 809 * Sets the last actor on a node (user who completed the task). 810 * 811 * @param actor the user id 812 */ 813 void setLastActor(String actor); 814 815 /** 816 * Evaluates the task assignees from the taskAssigneesVar 817 */ 818 List<String> evaluateTaskAssignees() throws DocumentRouteException; 819 820 /** 821 * Evaluates the task due date from the taskDueDateExpr and sets it as the dueDate 822 */ 823 Date computeTaskDueDate() throws DocumentRouteException; 824 825 /** 826 * Gets a map containing the workflow and node variables and workflow documents. 827 * 828 * @param detached The documents added into this map can be detached or not 829 */ 830 Map<String, Serializable> getWorkflowContextualInfo(CoreSession session, boolean detached); 831 832 /** 833 * When workflow engine runs an exclusive node, it evaluates the transition one by one and stops a soon as one of 834 * the transition is evaluated to true 835 * 836 * @since 5.7.2 837 */ 838 boolean executeOnlyFirstTransition(); 839 840 /** 841 * Checks if this node has a sub-route model defined. 842 * 843 * @return {@code true} if there is a sub-route 844 * @since 5.7.2 845 */ 846 boolean hasSubRoute() throws DocumentRouteException; 847 848 /** 849 * Gets the sub-route model id. 850 * <p> 851 * If this is present, then this node will be suspended while the sub-route is run. When the sub-route ends, this 852 * node will resume. 853 * 854 * @return the sub-route id, or {@code null} if none is defined 855 * @since 5.7.2 856 */ 857 String getSubRouteModelId() throws DocumentRouteException; 858 859 /** 860 * Starts the sub-route on this node. 861 * 862 * @return the sub-route 863 * @since 5.7.2 864 */ 865 DocumentRoute startSubRoute() throws DocumentRouteException; 866 867 /** 868 * Cancels the sub-route if there is one. 869 * 870 * @since 5.7.2 871 */ 872 void cancelSubRoute() throws DocumentRouteException; 873 874 /** 875 * Evaluates the rules for the escalation rules and returns the ones to be executed. The rules already executed and 876 * not having the property multipleExecution = true are also ignored 877 * 878 * @since 5.7.2 879 */ 880 List<EscalationRule> evaluateEscalationRules(); 881 882 /** 883 * Gets the list of all escalation rules for the node 884 * 885 * @since 5.7.2 886 */ 887 List<EscalationRule> getEscalationRules(); 888 889 /** 890 * Checks if this node has created multiple tasks, one for each assignees. 891 * 892 * @since 5.7.3 893 */ 894 boolean hasMultipleTasks(); 895 896 /** 897 * Gets all the tasks info for the tasks created from this node 898 * 899 * @since 5.7.3 900 */ 901 List<TaskInfo> getTasksInfo(); 902 903 /** 904 * Persist the info when a new task is created from this node 905 * 906 * @since 5.7.3 907 */ 908 void addTaskInfo(String taskId); 909 910 /** 911 * Persist these info from the task on the node. Status is the id of the button clicked to end the task by the 912 * actor. 913 * 914 * @since 5.7.3 915 */ 916 void updateTaskInfo(String taskId, boolean ended, String status, String actor, String comment); 917 918 /** 919 * Gets all the ended tasks originating from this node. This also counts the canceled tasks. 920 * 921 * @since 5.7.3 922 */ 923 List<TaskInfo> getEndedTasksInfo(); 924 925 /** 926 * Gets all the ended tasks originating from this node that were processed with a status. Doesn't count the canceled 927 * tasks. 928 * 929 * @since 5.7.3 930 */ 931 List<TaskInfo> getProcessedTasksInfo(); 932 933 /** 934 * Returns false if all tasks created from this node were ended. 935 * 936 * @since 5.7.3 937 */ 938 boolean hasOpenTasks(); 939 940 /** 941 * Returns true if tasks created from this node can be reassigned. 942 * 943 * @since 5.7.3 944 */ 945 boolean allowTaskReassignment(); 946 947 /** 948 * Sets the variable on this node if it exists as a Node Variable. 949 * 950 * @since 5.8 951 */ 952 void setVariable(String name, String value); 953 954 /** 955 * Sets the node variables. 956 * 957 * @since 5.9.3, 5.8.0-HF11 958 * @param map the map of variables 959 */ 960 void setVariables(Map<String, Serializable> map); 961 962 /** 963 * Sets the variables of the workflow based on their JSON representation (especially for scalar lists). Eg. 964 * Map<String, String> map = new HashMap<String, String>(); 965 * map.put("contributors","[\"John Doe\", \"John Smith\"]"); map.put("title","Test Title"); 966 * 967 * @param map the map of variables 968 * @since 5.9.3, 5.8.0-HF11 969 */ 970 void setJSONVariables(Map<String, String> map); 971 972 /** 973 * @since 7.4 974 */ 975 void removeTaskInfo(String taskId); 976 977}