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 * BETA! 024 */ 025@Experimental 026public class ConditionalTask extends AbstractTaskExecutor { 027 /** 028 * The task manager, used to synchronously run the other task 029 */ 030 private TaskManager taskManager; 031 032 /** 033 * A flag indicating that the task has been terminated 034 */ 035 private final AtomicBoolean terminated; 036 037 /** 038 * Constructs a new conditional task 039 */ 040 public ConditionalTask() { 041 this.terminated = new AtomicBoolean(); 042 } 043 044 @Override 045 public void execute(SailPointContext context, TaskSchedule taskSchedule, TaskResult taskResult, Attributes<String, Object> attributes) throws Exception { 046 TaskMonitor monitor = new TaskMonitor(context, taskResult); 047 super.setMonitor(monitor); 048 049 this.taskManager = new TaskManager(context); 050 051 boolean wait = attributes.getBoolean("awaitCompletion", false); 052 053 String ruleName = attributes.getString("conditionalRuleName"); 054 Rule conditionalRule = context.getObject(Rule.class, ruleName); 055 if (conditionalRule == null) { 056 throw new GeneralException("Unable to find conditional rule: " + ruleName); 057 } 058 059 String taskName = attributes.getString("taskName"); 060 TaskDefinition taskDef = context.getObject(TaskDefinition.class, taskName); 061 if (taskDef == null) { 062 throw new GeneralException("Unable to find child task: " + taskName); 063 } 064 065 Map<String, Object> inputs = new HashMap<>(); 066 067 Object ruleOutput = context.runRule(conditionalRule, inputs); 068 if (ruleOutput instanceof Boolean || ruleOutput instanceof String) { 069 boolean shouldRun = Utilities.isFlagSet(ruleOutput); 070 if (shouldRun) { 071 if (wait) { 072 TaskResult result = taskManager.runSync(taskDef, new HashMap<>()); 073 074 TaskResult parent = monitor.lockMasterResult(); 075 try { 076 parent.assimilateResult(result); 077 } finally { 078 monitor.commitMasterResult(); 079 } 080 } else { 081 TaskResult result = taskManager.runWithResult(taskDef, new HashMap<>()); 082 if (result != null) { 083 TaskResult parent = monitor.lockMasterResult(); 084 try { 085 parent.addMessage(Message.info("Launched child task " + result.getName())); 086 } finally { 087 monitor.commitMasterResult(); 088 } 089 } 090 } 091 } else { 092 TaskResult parent = monitor.lockMasterResult(); 093 try { 094 parent.addMessage(Message.info("Conditional rule returned false, indicating that task " + taskDef.getName() + " should be skipped")); 095 } finally { 096 monitor.commitMasterResult(); 097 } 098 } 099 } else { 100 throw new GeneralException("Illegal output of conditional rule: " + ruleOutput); 101 } 102 } 103 104 /** 105 * Terminates the task 106 * @return True, indicating that we have reacted to the termination 107 */ 108 @Override 109 public boolean terminate() { 110 this.terminated.set(true); 111 if (this.taskManager != null) { 112 this.taskManager.terminate(); 113 } 114 return true; 115 } 116}