View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.syncope.core.provisioning.java.data;
20  
21  import java.util.Objects;
22  import java.util.Optional;
23  import java.util.stream.Collectors;
24  import org.apache.commons.lang3.StringUtils;
25  import org.apache.syncope.common.lib.SyncopeClientException;
26  import org.apache.syncope.common.lib.command.CommandArgs;
27  import org.apache.syncope.common.lib.command.CommandTO;
28  import org.apache.syncope.common.lib.to.ExecTO;
29  import org.apache.syncope.common.lib.to.MacroTaskTO;
30  import org.apache.syncope.common.lib.to.NotificationTaskTO;
31  import org.apache.syncope.common.lib.to.PropagationTaskTO;
32  import org.apache.syncope.common.lib.to.ProvisioningTaskTO;
33  import org.apache.syncope.common.lib.to.PullTaskTO;
34  import org.apache.syncope.common.lib.to.PushTaskTO;
35  import org.apache.syncope.common.lib.to.SchedTaskTO;
36  import org.apache.syncope.common.lib.to.TaskTO;
37  import org.apache.syncope.common.lib.types.ClientExceptionType;
38  import org.apache.syncope.common.lib.types.IdRepoImplementationType;
39  import org.apache.syncope.common.lib.types.ImplementationEngine;
40  import org.apache.syncope.common.lib.types.JobType;
41  import org.apache.syncope.common.lib.types.MatchingRule;
42  import org.apache.syncope.common.lib.types.TaskType;
43  import org.apache.syncope.common.lib.types.UnmatchingRule;
44  import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
45  import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
46  import org.apache.syncope.core.persistence.api.dao.ImplementationDAO;
47  import org.apache.syncope.core.persistence.api.dao.NotFoundException;
48  import org.apache.syncope.core.persistence.api.dao.RealmDAO;
49  import org.apache.syncope.core.persistence.api.dao.TaskExecDAO;
50  import org.apache.syncope.core.persistence.api.entity.AnyType;
51  import org.apache.syncope.core.persistence.api.entity.EntityFactory;
52  import org.apache.syncope.core.persistence.api.entity.Implementation;
53  import org.apache.syncope.core.persistence.api.entity.task.AnyTemplatePullTask;
54  import org.apache.syncope.core.persistence.api.entity.task.MacroTask;
55  import org.apache.syncope.core.persistence.api.entity.task.NotificationTask;
56  import org.apache.syncope.core.persistence.api.entity.task.PropagationTask;
57  import org.apache.syncope.core.persistence.api.entity.task.ProvisioningTask;
58  import org.apache.syncope.core.persistence.api.entity.task.PullTask;
59  import org.apache.syncope.core.persistence.api.entity.task.PushTask;
60  import org.apache.syncope.core.persistence.api.entity.task.SchedTask;
61  import org.apache.syncope.core.persistence.api.entity.task.Task;
62  import org.apache.syncope.core.persistence.api.entity.task.TaskExec;
63  import org.apache.syncope.core.persistence.api.entity.task.TaskUtils;
64  import org.apache.syncope.core.persistence.api.entity.task.TaskUtilsFactory;
65  import org.apache.syncope.core.provisioning.api.data.TaskDataBinder;
66  import org.apache.syncope.core.provisioning.api.job.JobNamer;
67  import org.apache.syncope.core.provisioning.java.pushpull.PullJobDelegate;
68  import org.apache.syncope.core.provisioning.java.pushpull.PushJobDelegate;
69  import org.apache.syncope.core.provisioning.java.utils.TemplateUtils;
70  import org.apache.syncope.core.spring.implementation.ImplementationManager;
71  import org.quartz.Scheduler;
72  import org.quartz.SchedulerException;
73  import org.quartz.Trigger;
74  import org.quartz.TriggerKey;
75  import org.slf4j.Logger;
76  import org.slf4j.LoggerFactory;
77  import org.springframework.scheduling.quartz.SchedulerFactoryBean;
78  
79  public class TaskDataBinderImpl extends AbstractExecutableDatabinder implements TaskDataBinder {
80  
81      protected static final Logger LOG = LoggerFactory.getLogger(TaskDataBinder.class);
82  
83      protected static final String MACRO_RUN_JOB_DELEGATE = "org.apache.syncope.core.logic.job.MacroRunJobDelegate";
84  
85      protected final RealmDAO realmDAO;
86  
87      protected final ExternalResourceDAO resourceDAO;
88  
89      protected final TaskExecDAO taskExecDAO;
90  
91      protected final AnyTypeDAO anyTypeDAO;
92  
93      protected final ImplementationDAO implementationDAO;
94  
95      protected final EntityFactory entityFactory;
96  
97      protected final SchedulerFactoryBean scheduler;
98  
99      protected final TaskUtilsFactory taskUtilsFactory;
100 
101     public TaskDataBinderImpl(
102             final RealmDAO realmDAO,
103             final ExternalResourceDAO resourceDAO,
104             final TaskExecDAO taskExecDAO,
105             final AnyTypeDAO anyTypeDAO,
106             final ImplementationDAO implementationDAO,
107             final EntityFactory entityFactory,
108             final SchedulerFactoryBean scheduler,
109             final TaskUtilsFactory taskUtilsFactory) {
110 
111         this.realmDAO = realmDAO;
112         this.resourceDAO = resourceDAO;
113         this.taskExecDAO = taskExecDAO;
114         this.anyTypeDAO = anyTypeDAO;
115         this.implementationDAO = implementationDAO;
116         this.entityFactory = entityFactory;
117         this.scheduler = scheduler;
118         this.taskUtilsFactory = taskUtilsFactory;
119     }
120 
121     protected void fill(final ProvisioningTask<?> provisioningTask, final ProvisioningTaskTO provisioningTaskTO) {
122         if (provisioningTask instanceof PushTask && provisioningTaskTO instanceof PushTaskTO) {
123             PushTask pushTask = (PushTask) provisioningTask;
124             PushTaskTO pushTaskTO = (PushTaskTO) provisioningTaskTO;
125 
126             Implementation jobDelegate = pushTaskTO.getJobDelegate() == null
127                     ? implementationDAO.findByType(IdRepoImplementationType.TASKJOB_DELEGATE).stream().
128                             filter(impl -> PushJobDelegate.class.getSimpleName().equals(impl.getKey())).
129                             findFirst().orElse(null)
130                     : implementationDAO.find(pushTaskTO.getJobDelegate());
131             if (jobDelegate == null) {
132                 jobDelegate = entityFactory.newEntity(Implementation.class);
133                 jobDelegate.setKey(PushJobDelegate.class.getSimpleName());
134                 jobDelegate.setEngine(ImplementationEngine.JAVA);
135                 jobDelegate.setType(IdRepoImplementationType.TASKJOB_DELEGATE);
136                 jobDelegate.setBody(PushJobDelegate.class.getName());
137                 jobDelegate = implementationDAO.save(jobDelegate);
138             }
139             pushTask.setJobDelegate(jobDelegate);
140 
141             pushTask.setSourceRealm(realmDAO.findByFullPath(pushTaskTO.getSourceRealm()));
142 
143             pushTask.setMatchingRule(pushTaskTO.getMatchingRule() == null
144                     ? MatchingRule.LINK : pushTaskTO.getMatchingRule());
145             pushTask.setUnmatchingRule(pushTaskTO.getUnmatchingRule() == null
146                     ? UnmatchingRule.ASSIGN : pushTaskTO.getUnmatchingRule());
147 
148             pushTaskTO.getFilters().forEach((type, fiql) -> {
149                 AnyType anyType = anyTypeDAO.find(type);
150                 if (anyType == null) {
151                     LOG.debug("Invalid AnyType {} specified, ignoring...", type);
152                 } else {
153                     pushTask.getFilters().put(anyType.getKey(), fiql);
154                 }
155             });
156             // remove all filters not contained in the TO
157             pushTask.getFilters().entrySet().
158                     removeIf(filter -> !pushTaskTO.getFilters().containsKey(filter.getKey()));
159         } else if (provisioningTask instanceof PullTask && provisioningTaskTO instanceof PullTaskTO) {
160             PullTask pullTask = (PullTask) provisioningTask;
161             PullTaskTO pullTaskTO = (PullTaskTO) provisioningTaskTO;
162 
163             Implementation jobDelegate = pullTaskTO.getJobDelegate() == null
164                     ? implementationDAO.findByType(IdRepoImplementationType.TASKJOB_DELEGATE).stream().
165                             filter(impl -> PullJobDelegate.class.getSimpleName().equals(impl.getKey())).
166                             findFirst().orElse(null)
167                     : implementationDAO.find(pullTaskTO.getJobDelegate());
168             if (jobDelegate == null) {
169                 jobDelegate = entityFactory.newEntity(Implementation.class);
170                 jobDelegate.setKey(PullJobDelegate.class.getSimpleName());
171                 jobDelegate.setEngine(ImplementationEngine.JAVA);
172                 jobDelegate.setType(IdRepoImplementationType.TASKJOB_DELEGATE);
173                 jobDelegate.setBody(PullJobDelegate.class.getName());
174                 jobDelegate = implementationDAO.save(jobDelegate);
175             }
176             pullTask.setJobDelegate(jobDelegate);
177 
178             pullTask.setPullMode(pullTaskTO.getPullMode());
179 
180             if (pullTaskTO.getReconFilterBuilder() == null) {
181                 pullTask.setReconFilterBuilder(null);
182             } else {
183                 Optional.ofNullable(implementationDAO.find(pullTaskTO.getReconFilterBuilder())).ifPresentOrElse(
184                         pullTask::setReconFilterBuilder,
185                         () -> LOG.debug("Invalid Implementation {}, ignoring...", pullTaskTO.getReconFilterBuilder()));
186             }
187 
188             pullTask.setDestinationRealm(realmDAO.findByFullPath(pullTaskTO.getDestinationRealm()));
189 
190             pullTask.setMatchingRule(pullTaskTO.getMatchingRule() == null
191                     ? MatchingRule.UPDATE : pullTaskTO.getMatchingRule());
192             pullTask.setUnmatchingRule(pullTaskTO.getUnmatchingRule() == null
193                     ? UnmatchingRule.PROVISION : pullTaskTO.getUnmatchingRule());
194 
195             // validate JEXL expressions from templates and proceed if fine
196             TemplateUtils.check(pullTaskTO.getTemplates(), ClientExceptionType.InvalidPullTask);
197             pullTaskTO.getTemplates().forEach((type, template) -> {
198                 AnyType anyType = anyTypeDAO.find(type);
199                 if (anyType == null) {
200                     LOG.debug("Invalid AnyType {} specified, ignoring...", type);
201                 } else {
202                     AnyTemplatePullTask anyTemplate = pullTask.getTemplate(anyType.getKey()).orElse(null);
203                     if (anyTemplate == null) {
204                         anyTemplate = entityFactory.newEntity(AnyTemplatePullTask.class);
205                         anyTemplate.setAnyType(anyType);
206                         anyTemplate.setPullTask(pullTask);
207 
208                         pullTask.add(anyTemplate);
209                     }
210                     anyTemplate.set(template);
211                 }
212             });
213             // remove all templates not contained in the TO
214             pullTask.getTemplates().
215                     removeIf(anyTemplate -> !pullTaskTO.getTemplates().containsKey(anyTemplate.getAnyType().getKey()));
216 
217             pullTask.setRemediation(pullTaskTO.isRemediation());
218         }
219 
220         // 3. fill the remaining fields
221         provisioningTask.setPerformCreate(provisioningTaskTO.isPerformCreate());
222         provisioningTask.setPerformUpdate(provisioningTaskTO.isPerformUpdate());
223         provisioningTask.setPerformDelete(provisioningTaskTO.isPerformDelete());
224         provisioningTask.setSyncStatus(provisioningTaskTO.isSyncStatus());
225 
226         provisioningTaskTO.getActions().forEach(
227                 action -> Optional.ofNullable(implementationDAO.find(action)).ifPresentOrElse(
228                         provisioningTask::add,
229                         () -> LOG.debug("Invalid Implementation {}, ignoring...", action)));
230         // remove all implementations not contained in the TO
231         provisioningTask.getActions().removeIf(impl -> !provisioningTaskTO.getActions().contains(impl.getKey()));
232 
233         provisioningTask.setConcurrentSettings(provisioningTaskTO.getConcurrentSettings());
234     }
235 
236     protected void fill(final MacroTask macroTask, final MacroTaskTO macroTaskTO) {
237         macroTask.setRealm(Optional.ofNullable(realmDAO.findByFullPath(macroTaskTO.getRealm())).
238                 orElseThrow(() -> new NotFoundException("Realm " + macroTaskTO.getRealm())));
239 
240         macroTaskTO.getCommands().
241                 forEach(command -> Optional.ofNullable(implementationDAO.find(command.getKey())).ifPresentOrElse(
242                 impl -> {
243                     try {
244                         CommandArgs args = command.getArgs();
245                         if (args == null) {
246                             args = ImplementationManager.emptyArgs(impl);
247                         }
248 
249                         macroTask.add(impl, args);
250                     } catch (Exception e) {
251                         LOG.error("While adding Command {} to Macro", impl.getKey(), e);
252 
253                         SyncopeClientException sce = SyncopeClientException.build(
254                                 ClientExceptionType.InvalidImplementationType);
255                         sce.getElements().add("While adding Command " + impl.getKey() + ": " + e.getMessage());
256                         throw sce;
257                     }
258                 },
259                 () -> LOG.error("Could not find Command {}", command.getKey())));
260 
261         macroTask.setContinueOnError(macroTaskTO.isContinueOnError());
262         macroTask.setSaveExecs(macroTaskTO.isSaveExecs());
263     }
264 
265     @Override
266     public SchedTask createSchedTask(final SchedTaskTO taskTO, final TaskUtils taskUtils) {
267         Class<? extends TaskTO> taskTOClass = taskUtils.taskTOClass();
268         if (taskTOClass == null || !taskTOClass.equals(taskTO.getClass())) {
269             throw new IllegalArgumentException(String.format("Expected %s, found %s", taskTOClass, taskTO.getClass()));
270         }
271 
272         SchedTask task = taskUtils.newTask();
273         task.setStartAt(taskTO.getStartAt());
274         task.setCronExpression(taskTO.getCronExpression());
275         task.setName(taskTO.getName());
276         task.setDescription(taskTO.getDescription());
277         task.setActive(taskTO.isActive());
278 
279         if (taskUtils.getType() == TaskType.SCHEDULED) {
280             task.setJobDelegate(Optional.ofNullable(implementationDAO.find(taskTO.getJobDelegate())).
281                     orElseThrow(() -> new NotFoundException("JobDelegate " + taskTO.getJobDelegate())));
282         } else if (taskTO instanceof MacroTaskTO) {
283             MacroTaskTO macroTaskTO = (MacroTaskTO) taskTO;
284             MacroTask macroTask = (MacroTask) task;
285 
286             Implementation jobDelegate = macroTaskTO.getJobDelegate() == null
287                     ? implementationDAO.findByType(IdRepoImplementationType.TASKJOB_DELEGATE).stream().
288                             filter(impl -> MACRO_RUN_JOB_DELEGATE.equals(impl.getBody())).
289                             findFirst().orElse(null)
290                     : implementationDAO.find(macroTaskTO.getJobDelegate());
291             if (jobDelegate == null) {
292                 jobDelegate = entityFactory.newEntity(Implementation.class);
293                 jobDelegate.setKey(StringUtils.substringAfterLast(MACRO_RUN_JOB_DELEGATE, "."));
294                 jobDelegate.setEngine(ImplementationEngine.JAVA);
295                 jobDelegate.setType(IdRepoImplementationType.TASKJOB_DELEGATE);
296                 jobDelegate.setBody(MACRO_RUN_JOB_DELEGATE);
297                 jobDelegate = implementationDAO.save(jobDelegate);
298             }
299             macroTask.setJobDelegate(jobDelegate);
300 
301             macroTask.setRealm(Optional.ofNullable(realmDAO.findByFullPath(macroTaskTO.getRealm())).
302                     orElseThrow(() -> new NotFoundException("Realm " + macroTaskTO.getRealm())));
303 
304             fill(macroTask, macroTaskTO);
305         } else if (taskTO instanceof ProvisioningTaskTO) {
306             ProvisioningTaskTO provisioningTaskTO = (ProvisioningTaskTO) taskTO;
307             ProvisioningTask<?> provisioningTask = (ProvisioningTask<?>) task;
308 
309             provisioningTask.setResource(Optional.ofNullable(resourceDAO.find(provisioningTaskTO.getResource())).
310                     orElseThrow(() -> new NotFoundException("Resource " + provisioningTaskTO.getResource())));
311 
312             fill(provisioningTask, provisioningTaskTO);
313         }
314 
315         return task;
316     }
317 
318     @Override
319     public void updateSchedTask(final SchedTask task, final SchedTaskTO taskTO, final TaskUtils taskUtils) {
320         Class<? extends TaskTO> taskTOClass = taskUtils.taskTOClass();
321         if (taskTOClass == null || !taskTOClass.equals(taskTO.getClass())) {
322             throw new IllegalArgumentException(String.format("Expected %s, found %s", taskTOClass, taskTO.getClass()));
323         }
324 
325         if (StringUtils.isBlank(taskTO.getName())) {
326             SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.RequiredValuesMissing);
327             sce.getElements().add("name");
328             throw sce;
329         }
330 
331         task.setName(taskTO.getName());
332         task.setDescription(taskTO.getDescription());
333         task.setCronExpression(taskTO.getCronExpression());
334         task.setActive(taskTO.isActive());
335 
336         if (task instanceof MacroTask) {
337             MacroTaskTO macroTaskTO = (MacroTaskTO) taskTO;
338             MacroTask macroTask = (MacroTask) task;
339 
340             macroTask.getCommands().clear();
341             macroTask.getCommandArgs().clear();
342 
343             fill(macroTask, macroTaskTO);
344         } else if (task instanceof ProvisioningTask) {
345             fill((ProvisioningTask) task, (ProvisioningTaskTO) taskTO);
346         }
347     }
348 
349     @Override
350     public String buildRefDesc(final Task<?> task) {
351         return taskUtilsFactory.getInstance(task).getType().name() + ' '
352                 + "Task "
353                 + task.getKey() + ' '
354                 + (task instanceof SchedTask
355                         ? SchedTask.class.cast(task).getName()
356                         : task instanceof PropagationTask
357                                 ? PropagationTask.class.cast(task).getConnObjectKey()
358                                 : StringUtils.EMPTY);
359     }
360 
361     @Override
362     public ExecTO getExecTO(final TaskExec<?> execution) {
363         ExecTO execTO = new ExecTO();
364         execTO.setKey(execution.getKey());
365         execTO.setStatus(execution.getStatus());
366         execTO.setMessage(execution.getMessage());
367         execTO.setStart(execution.getStart());
368         execTO.setEnd(execution.getEnd());
369         execTO.setExecutor(execution.getExecutor());
370 
371         if (execution.getTask() != null && execution.getTask().getKey() != null) {
372             execTO.setJobType(JobType.TASK);
373             execTO.setRefKey(execution.getTask().getKey());
374             execTO.setRefDesc(buildRefDesc(execution.getTask()));
375         }
376 
377         return execTO;
378     }
379 
380     protected void fill(final SchedTaskTO schedTaskTO, final SchedTask schedTask) {
381         schedTaskTO.setName(schedTask.getName());
382         schedTaskTO.setDescription(schedTask.getDescription());
383         schedTaskTO.setCronExpression(schedTask.getCronExpression());
384         schedTaskTO.setActive(schedTask.isActive());
385 
386         schedTaskTO.setLastExec(schedTaskTO.getStart());
387 
388         String triggerName = JobNamer.getTriggerName(JobNamer.getJobKey(schedTask).getName());
389         try {
390             Trigger trigger = scheduler.getScheduler().getTrigger(new TriggerKey(triggerName, Scheduler.DEFAULT_GROUP));
391             if (trigger != null) {
392                 schedTaskTO.setLastExec(toOffsetDateTime(trigger.getPreviousFireTime()));
393                 schedTaskTO.setNextExec(toOffsetDateTime(trigger.getNextFireTime()));
394             }
395         } catch (SchedulerException e) {
396             LOG.warn("While trying to get to " + triggerName, e);
397         }
398 
399         if (schedTaskTO instanceof ProvisioningTaskTO && schedTask instanceof ProvisioningTask) {
400             ProvisioningTaskTO provisioningTaskTO = (ProvisioningTaskTO) schedTaskTO;
401             ProvisioningTask<?> provisioningTask = (ProvisioningTask<?>) schedTask;
402 
403             provisioningTaskTO.setResource(provisioningTask.getResource().getKey());
404 
405             provisioningTaskTO.getActions().addAll(
406                     provisioningTask.getActions().stream().map(Implementation::getKey).collect(Collectors.toList()));
407 
408             provisioningTaskTO.setPerformCreate(provisioningTask.isPerformCreate());
409             provisioningTaskTO.setPerformUpdate(provisioningTask.isPerformUpdate());
410             provisioningTaskTO.setPerformDelete(provisioningTask.isPerformDelete());
411             provisioningTaskTO.setSyncStatus(provisioningTask.isSyncStatus());
412 
413             provisioningTaskTO.setConcurrentSettings(provisioningTask.getConcurrentSettings());
414         }
415     }
416 
417     @Override
418     public <T extends TaskTO> T getTaskTO(final Task<?> task, final TaskUtils taskUtils, final boolean details) {
419         T taskTO = taskUtils.newTaskTO();
420         taskTO.setKey(task.getKey());
421 
422         Optional.ofNullable(taskExecDAO.findLatestStarted(taskUtils.getType(), task)).ifPresentOrElse(
423                 latestExec -> {
424                     taskTO.setLatestExecStatus(latestExec.getStatus());
425                     taskTO.setStart(latestExec.getStart());
426                     taskTO.setEnd(latestExec.getEnd());
427                     taskTO.setLastExecutor(latestExec.getExecutor());
428                 },
429                 () -> taskTO.setLatestExecStatus(StringUtils.EMPTY));
430 
431         if (details) {
432             task.getExecs().stream().
433                     filter(Objects::nonNull).
434                     forEach(execution -> taskTO.getExecutions().add(getExecTO(execution)));
435         }
436 
437         switch (taskUtils.getType()) {
438             case PROPAGATION:
439                 PropagationTask propagationTask = (PropagationTask) task;
440                 PropagationTaskTO propagationTaskTO = (PropagationTaskTO) taskTO;
441 
442                 propagationTaskTO.setOperation(propagationTask.getOperation());
443                 propagationTaskTO.setConnObjectKey(propagationTask.getConnObjectKey());
444                 propagationTaskTO.setOldConnObjectKey(propagationTask.getOldConnObjectKey());
445                 propagationTaskTO.setPropagationData(propagationTask.getSerializedPropagationData());
446                 propagationTaskTO.setResource(propagationTask.getResource().getKey());
447                 propagationTaskTO.setObjectClassName(propagationTask.getObjectClassName());
448                 propagationTaskTO.setAnyTypeKind(propagationTask.getAnyTypeKind());
449                 propagationTaskTO.setAnyType(propagationTask.getAnyType());
450                 propagationTaskTO.setEntityKey(propagationTask.getEntityKey());
451                 break;
452 
453             case SCHEDULED:
454                 SchedTask schedTask = (SchedTask) task;
455                 SchedTaskTO schedTaskTO = (SchedTaskTO) taskTO;
456 
457                 schedTaskTO.setJobDelegate(schedTask.getJobDelegate().getKey());
458 
459                 fill(schedTaskTO, schedTask);
460                 break;
461 
462             case MACRO:
463                 MacroTask macroTask = (MacroTask) task;
464                 MacroTaskTO macroTaskTO = (MacroTaskTO) taskTO;
465 
466                 macroTaskTO.setJobDelegate(macroTask.getJobDelegate().getKey());
467                 macroTaskTO.setRealm(macroTask.getRealm().getFullPath());
468                 for (int i = 0; i < macroTask.getCommands().size(); i++) {
469                     macroTaskTO.getCommands().add(
470                             new CommandTO.Builder(macroTask.getCommands().get(i).getKey()).
471                                     args(macroTask.getCommandArgs().get(i)).build());
472                 }
473                 macroTaskTO.setContinueOnError(macroTask.isContinueOnError());
474                 macroTaskTO.setSaveExecs(macroTask.isSaveExecs());
475 
476                 fill(macroTaskTO, macroTask);
477                 break;
478 
479             case PULL:
480                 PullTask pullTask = (PullTask) task;
481                 PullTaskTO pullTaskTO = (PullTaskTO) taskTO;
482 
483                 fill(pullTaskTO, pullTask);
484 
485                 pullTaskTO.setDestinationRealm(pullTask.getDestinationRealm().getFullPath());
486                 pullTaskTO.setMatchingRule(pullTask.getMatchingRule() == null
487                         ? MatchingRule.UPDATE : pullTask.getMatchingRule());
488                 pullTaskTO.setUnmatchingRule(pullTask.getUnmatchingRule() == null
489                         ? UnmatchingRule.PROVISION : pullTask.getUnmatchingRule());
490                 pullTaskTO.setPullMode(pullTask.getPullMode());
491 
492                 if (pullTask.getReconFilterBuilder() != null) {
493                     pullTaskTO.setReconFilterBuilder(pullTask.getReconFilterBuilder().getKey());
494                 }
495 
496                 pullTask.getTemplates().
497                         forEach(template -> pullTaskTO.getTemplates().
498                         put(template.getAnyType().getKey(), template.get()));
499 
500                 pullTaskTO.setRemediation(pullTask.isRemediation());
501                 break;
502 
503             case PUSH:
504                 PushTask pushTask = (PushTask) task;
505                 PushTaskTO pushTaskTO = (PushTaskTO) taskTO;
506 
507                 fill(pushTaskTO, pushTask);
508 
509                 pushTaskTO.setSourceRealm(pushTask.getSourceRealm().getFullPath());
510                 pushTaskTO.setMatchingRule(pushTask.getMatchingRule() == null
511                         ? MatchingRule.LINK : pushTask.getMatchingRule());
512                 pushTaskTO.setUnmatchingRule(pushTask.getUnmatchingRule() == null
513                         ? UnmatchingRule.ASSIGN : pushTask.getUnmatchingRule());
514 
515                 pushTaskTO.getFilters().putAll(pushTask.getFilters());
516                 break;
517 
518             case NOTIFICATION:
519                 NotificationTask notificationTask = (NotificationTask) task;
520                 NotificationTaskTO notificationTaskTO = (NotificationTaskTO) taskTO;
521 
522                 notificationTaskTO.setNotification(notificationTask.getNotification().getKey());
523                 notificationTaskTO.setAnyTypeKind(notificationTask.getAnyTypeKind());
524                 notificationTaskTO.setEntityKey(notificationTask.getEntityKey());
525                 notificationTaskTO.setSender(notificationTask.getSender());
526                 notificationTaskTO.getRecipients().addAll(notificationTask.getRecipients());
527                 notificationTaskTO.setSubject(notificationTask.getSubject());
528                 notificationTaskTO.setHtmlBody(notificationTask.getHtmlBody());
529                 notificationTaskTO.setTextBody(notificationTask.getTextBody());
530                 notificationTaskTO.setExecuted(notificationTask.isExecuted());
531                 if (notificationTask.isExecuted() && StringUtils.isBlank(taskTO.getLatestExecStatus())) {
532                     taskTO.setLatestExecStatus("[EXECUTED]");
533                 }
534                 notificationTaskTO.setTraceLevel(notificationTask.getTraceLevel());
535                 break;
536 
537             default:
538         }
539 
540         return taskTO;
541     }
542 }