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}