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