001package com.identityworksllc.iiq.common.task;
002
003import com.identityworksllc.iiq.common.Utilities;
004import com.identityworksllc.iiq.common.annotation.Experimental;
005import sailpoint.api.SailPointContext;
006import sailpoint.api.TaskManager;
007import sailpoint.object.*;
008import sailpoint.task.AbstractTaskExecutor;
009import sailpoint.task.TaskMonitor;
010import sailpoint.tools.GeneralException;
011import sailpoint.tools.Message;
012
013import java.util.HashMap;
014import java.util.Map;
015import java.util.concurrent.atomic.AtomicBoolean;
016
017/**
018 * A task executor that will invoke a Rule that returns a boolean indicating that
019 * another task should be run. This can be used to skip an expensive task, or a task
020 * likely to cause problems, such as during externally defined maintenance windows,
021 * final exam periods, or other critical times.
022 *
023 */
024public class ConditionalTask extends AbstractTaskExecutor {
025    /**
026     * The task manager, used to synchronously run the other task
027     */
028    private TaskManager taskManager;
029
030    /**
031     * A flag indicating that the task has been terminated
032     */
033    private final AtomicBoolean terminated;
034
035    /**
036     * Constructs a new conditional task
037     */
038    public ConditionalTask() {
039        this.terminated = new AtomicBoolean();
040    }
041
042    @Override
043    public void execute(SailPointContext context, TaskSchedule taskSchedule, TaskResult taskResult, Attributes<String, Object> attributes) throws Exception {
044        TaskMonitor monitor = new TaskMonitor(context, taskResult);
045        super.setMonitor(monitor);
046
047        this.taskManager = new TaskManager(context);
048
049        boolean wait = attributes.getBoolean("awaitCompletion", false);
050
051        String ruleName = attributes.getString("conditionalRuleName");
052        Rule conditionalRule = context.getObject(Rule.class, ruleName);
053        if (conditionalRule == null) {
054            throw new GeneralException("Unable to find conditional rule: " + ruleName);
055        }
056
057        String taskName = attributes.getString("taskName");
058        TaskDefinition taskDef = context.getObject(TaskDefinition.class, taskName);
059        if (taskDef == null) {
060            throw new GeneralException("Unable to find child task: " + taskName);
061        }
062
063        Map<String, Object> inputs = new HashMap<>();
064
065        Object ruleOutput = context.runRule(conditionalRule, inputs);
066        if (ruleOutput instanceof Boolean || ruleOutput instanceof String) {
067            boolean shouldRun = Utilities.isFlagSet(ruleOutput);
068            if (shouldRun) {
069                if (wait) {
070                    TaskResult result = taskManager.runSync(taskDef, new HashMap<>());
071
072                    TaskResult parent = monitor.lockMasterResult();
073                    try {
074                        parent.assimilateResult(result);
075                    } finally {
076                        monitor.commitMasterResult();
077                    }
078                } else {
079                    TaskResult result = taskManager.runWithResult(taskDef, new HashMap<>());
080                    if (result != null) {
081                        TaskResult parent = monitor.lockMasterResult();
082                        try {
083                            parent.addMessage(Message.info("Launched child task " + result.getName()));
084                        } finally {
085                            monitor.commitMasterResult();
086                        }
087                    }
088                }
089            } else {
090                TaskResult parent = monitor.lockMasterResult();
091                try {
092                    parent.addMessage(Message.info("Conditional rule returned false, indicating that task " + taskDef.getName() + " should be skipped"));
093                } finally {
094                    monitor.commitMasterResult();
095                }
096            }
097        } else {
098            throw new GeneralException("Illegal output of conditional rule: " + ruleOutput);
099        }
100    }
101
102    /**
103     * Terminates the task
104     * @return True, indicating that we have reacted to the termination
105     */
106    @Override
107    public boolean terminate() {
108        this.terminated.set(true);
109        if (this.taskManager != null) {
110            this.taskManager.terminate();
111        }
112        return true;
113    }
114}