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