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