1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.syncope.core.provisioning.java.pushpull;
20
21 import java.lang.reflect.ParameterizedType;
22 import java.util.ArrayList;
23 import java.util.Collection;
24 import java.util.List;
25 import java.util.Objects;
26 import java.util.Optional;
27 import org.apache.commons.lang3.StringUtils;
28 import org.apache.syncope.common.lib.to.Mapping;
29 import org.apache.syncope.common.lib.to.Provision;
30 import org.apache.syncope.common.lib.to.ProvisioningReport;
31 import org.apache.syncope.common.lib.types.AnyTypeKind;
32 import org.apache.syncope.common.lib.types.TraceLevel;
33 import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
34 import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
35 import org.apache.syncope.core.persistence.api.dao.PolicyDAO;
36 import org.apache.syncope.core.persistence.api.entity.EntityFactory;
37 import org.apache.syncope.core.persistence.api.entity.ExternalResource;
38 import org.apache.syncope.core.persistence.api.entity.task.ProvisioningTask;
39 import org.apache.syncope.core.persistence.api.entity.task.TaskExec;
40 import org.apache.syncope.core.provisioning.api.Connector;
41 import org.apache.syncope.core.provisioning.api.ConnectorManager;
42 import org.apache.syncope.core.provisioning.api.ProvisionSorter;
43 import org.apache.syncope.core.provisioning.java.job.AbstractSchedTaskJobDelegate;
44 import org.apache.syncope.core.provisioning.java.job.TaskJob;
45 import org.apache.syncope.core.spring.implementation.ImplementationManager;
46 import org.quartz.JobExecutionContext;
47 import org.quartz.JobExecutionException;
48 import org.springframework.beans.factory.annotation.Autowired;
49
50 public abstract class AbstractProvisioningJobDelegate<T extends ProvisioningTask<T>>
51 extends AbstractSchedTaskJobDelegate<T> {
52
53 private static final String USER = "USER";
54
55 private static final String GROUP = "GROUP";
56
57 private static final String LINKED_ACCOUNT = "LINKED_ACCOUNT";
58
59
60
61
62 @Autowired
63 protected ConnectorManager connectorManager;
64
65
66
67
68 @Autowired
69 protected AnyTypeDAO anyTypeDAO;
70
71
72
73
74 @Autowired
75 protected ExternalResourceDAO resourceDAO;
76
77 @Autowired
78 protected EntityFactory entityFactory;
79
80
81
82
83 @Autowired
84 protected PolicyDAO policyDAO;
85
86 protected Optional<ProvisionSorter> perContextProvisionSorter = Optional.empty();
87
88 protected ProvisionSorter getProvisionSorter(final T task) {
89 if (task.getResource().getProvisionSorter() != null) {
90 try {
91 return ImplementationManager.build(
92 task.getResource().getProvisionSorter(),
93 () -> perContextProvisionSorter.orElse(null),
94 instance -> perContextProvisionSorter = Optional.of(instance));
95 } catch (Exception e) {
96 LOG.error("While building {}", task.getResource().getProvisionSorter(), e);
97 }
98 }
99
100 if (perContextProvisionSorter.isEmpty()) {
101 perContextProvisionSorter = Optional.of(new DefaultProvisionSorter());
102 }
103 return perContextProvisionSorter.get();
104 }
105
106
107
108
109
110
111
112
113 protected String generate(final Collection<ProvisioningReport> results, final TraceLevel level) {
114 StringBuilder sb = new StringBuilder();
115
116 results.stream().map(result -> {
117 if (level == TraceLevel.SUMMARY) {
118
119 return null;
120 } else if (level == TraceLevel.FAILURES && result.getStatus() == ProvisioningReport.Status.FAILURE) {
121
122 return String.format("Failed %s (key/name): %s/%s with message: %s",
123 result.getOperation(), result.getKey(), result.getName(), result.getMessage());
124 } else {
125
126 return String.format("%s %s (key/name): %s/%s %s",
127 result.getOperation(), result.getStatus(), result.getKey(), result.getName(),
128 StringUtils.isBlank(result.getMessage())
129 ? StringUtils.EMPTY
130 : "with message: " + result.getMessage());
131 }
132 }).filter(Objects::nonNull).forEach(report -> sb.append(report).append('\n'));
133
134 return sb.toString();
135 }
136
137
138
139
140
141
142
143
144
145 protected String createReport(
146 final Collection<ProvisioningReport> provResults,
147 final ExternalResource resource,
148 final boolean dryRun) {
149
150 TraceLevel traceLevel = resource.getProvisioningTraceLevel();
151 if (traceLevel == TraceLevel.NONE) {
152 return null;
153 }
154
155 StringBuilder report = new StringBuilder();
156
157 if (dryRun) {
158 report.append("==> Dry run only, no modifications were made <==\n\n");
159 }
160 if (interrupted) {
161 report.append("==> Execution was interrupted <==\n\n");
162 }
163
164 List<ProvisioningReport> rSuccCreate = new ArrayList<>();
165 List<ProvisioningReport> rFailCreate = new ArrayList<>();
166 List<ProvisioningReport> rSuccUpdate = new ArrayList<>();
167 List<ProvisioningReport> rFailUpdate = new ArrayList<>();
168 List<ProvisioningReport> rSuccDelete = new ArrayList<>();
169 List<ProvisioningReport> rFailDelete = new ArrayList<>();
170 List<ProvisioningReport> rSuccNone = new ArrayList<>();
171 List<ProvisioningReport> rIgnore = new ArrayList<>();
172 List<ProvisioningReport> uSuccCreate = new ArrayList<>();
173 List<ProvisioningReport> uFailCreate = new ArrayList<>();
174 List<ProvisioningReport> uSuccUpdate = new ArrayList<>();
175 List<ProvisioningReport> uFailUpdate = new ArrayList<>();
176 List<ProvisioningReport> uSuccDelete = new ArrayList<>();
177 List<ProvisioningReport> uFailDelete = new ArrayList<>();
178 List<ProvisioningReport> uSuccNone = new ArrayList<>();
179 List<ProvisioningReport> uIgnore = new ArrayList<>();
180 List<ProvisioningReport> gSuccCreate = new ArrayList<>();
181 List<ProvisioningReport> gFailCreate = new ArrayList<>();
182 List<ProvisioningReport> gSuccUpdate = new ArrayList<>();
183 List<ProvisioningReport> gFailUpdate = new ArrayList<>();
184 List<ProvisioningReport> gSuccDelete = new ArrayList<>();
185 List<ProvisioningReport> gFailDelete = new ArrayList<>();
186 List<ProvisioningReport> gSuccNone = new ArrayList<>();
187 List<ProvisioningReport> gIgnore = new ArrayList<>();
188 List<ProvisioningReport> aSuccCreate = new ArrayList<>();
189 List<ProvisioningReport> aFailCreate = new ArrayList<>();
190 List<ProvisioningReport> aSuccUpdate = new ArrayList<>();
191 List<ProvisioningReport> aFailUpdate = new ArrayList<>();
192 List<ProvisioningReport> aSuccDelete = new ArrayList<>();
193 List<ProvisioningReport> aFailDelete = new ArrayList<>();
194 List<ProvisioningReport> aSuccNone = new ArrayList<>();
195 List<ProvisioningReport> aIgnore = new ArrayList<>();
196 List<ProvisioningReport> laSuccCreate = new ArrayList<>();
197 List<ProvisioningReport> laFailCreate = new ArrayList<>();
198 List<ProvisioningReport> laSuccUpdate = new ArrayList<>();
199 List<ProvisioningReport> laFailUpdate = new ArrayList<>();
200 List<ProvisioningReport> laSuccDelete = new ArrayList<>();
201 List<ProvisioningReport> laFailDelete = new ArrayList<>();
202 List<ProvisioningReport> laSuccNone = new ArrayList<>();
203 List<ProvisioningReport> laIgnore = new ArrayList<>();
204
205 for (ProvisioningReport provResult : provResults) {
206 switch (provResult.getStatus()) {
207 case SUCCESS:
208 switch (provResult.getOperation()) {
209 case CREATE:
210 if (StringUtils.isBlank(provResult.getAnyType())) {
211 rSuccCreate.add(provResult);
212 } else {
213 switch (provResult.getAnyType()) {
214 case USER:
215 uSuccCreate.add(provResult);
216 break;
217
218 case LINKED_ACCOUNT:
219 laSuccCreate.add(provResult);
220 break;
221
222 case GROUP:
223 gSuccCreate.add(provResult);
224 break;
225
226 default:
227 aSuccCreate.add(provResult);
228 }
229 }
230 break;
231
232 case UPDATE:
233 if (StringUtils.isBlank(provResult.getAnyType())) {
234 rSuccUpdate.add(provResult);
235 } else {
236 switch (provResult.getAnyType()) {
237 case USER:
238 uSuccUpdate.add(provResult);
239 break;
240
241 case LINKED_ACCOUNT:
242 laSuccUpdate.add(provResult);
243 break;
244
245 case GROUP:
246 gSuccUpdate.add(provResult);
247 break;
248
249 default:
250 aSuccUpdate.add(provResult);
251 }
252 }
253 break;
254
255 case DELETE:
256 if (StringUtils.isBlank(provResult.getAnyType())) {
257 rSuccDelete.add(provResult);
258 } else {
259 switch (provResult.getAnyType()) {
260 case USER:
261 uSuccDelete.add(provResult);
262 break;
263
264 case LINKED_ACCOUNT:
265 laSuccDelete.add(provResult);
266 break;
267
268 case GROUP:
269 gSuccDelete.add(provResult);
270 break;
271
272 default:
273 aSuccDelete.add(provResult);
274 }
275 }
276 break;
277
278 case NONE:
279 if (StringUtils.isBlank(provResult.getAnyType())) {
280 rSuccNone.add(provResult);
281 } else {
282 switch (provResult.getAnyType()) {
283 case USER:
284 uSuccNone.add(provResult);
285 break;
286
287 case LINKED_ACCOUNT:
288 laSuccNone.add(provResult);
289 break;
290
291 case GROUP:
292 gSuccNone.add(provResult);
293 break;
294
295 default:
296 aSuccNone.add(provResult);
297 }
298 }
299 break;
300
301 default:
302 }
303 break;
304
305 case FAILURE:
306 switch (provResult.getOperation()) {
307 case CREATE:
308 if (StringUtils.isBlank(provResult.getAnyType())) {
309 rFailCreate.add(provResult);
310 } else {
311 switch (provResult.getAnyType()) {
312 case USER:
313 uFailCreate.add(provResult);
314 break;
315
316 case LINKED_ACCOUNT:
317 laFailCreate.add(provResult);
318 break;
319
320 case GROUP:
321 gFailCreate.add(provResult);
322 break;
323
324 default:
325 aFailCreate.add(provResult);
326 }
327 }
328 break;
329
330 case UPDATE:
331 if (StringUtils.isBlank(provResult.getAnyType())) {
332 rFailUpdate.add(provResult);
333 } else {
334 switch (provResult.getAnyType()) {
335 case USER:
336 uFailUpdate.add(provResult);
337 break;
338
339 case LINKED_ACCOUNT:
340 laFailUpdate.add(provResult);
341 break;
342
343 case GROUP:
344 gFailUpdate.add(provResult);
345 break;
346
347 default:
348 aFailUpdate.add(provResult);
349 }
350 }
351 break;
352
353 case DELETE:
354 if (StringUtils.isBlank(provResult.getAnyType())) {
355 rFailDelete.add(provResult);
356 } else {
357 switch (provResult.getAnyType()) {
358 case USER:
359 uFailDelete.add(provResult);
360 break;
361
362 case LINKED_ACCOUNT:
363 laFailDelete.add(provResult);
364 break;
365
366 case GROUP:
367 gFailDelete.add(provResult);
368 break;
369
370 default:
371 aFailDelete.add(provResult);
372 }
373 }
374 break;
375
376 default:
377 }
378 break;
379
380 case IGNORE:
381 if (StringUtils.isBlank(provResult.getAnyType())) {
382 rIgnore.add(provResult);
383 } else {
384 switch (provResult.getAnyType()) {
385 case USER:
386 uIgnore.add(provResult);
387 break;
388
389 case LINKED_ACCOUNT:
390 laIgnore.add(provResult);
391 break;
392
393 case GROUP:
394 gIgnore.add(provResult);
395 break;
396
397 default:
398 aIgnore.add(provResult);
399 }
400 }
401 break;
402
403 default:
404 }
405 }
406
407
408 boolean includeUser = resource.getProvisionByAnyType(AnyTypeKind.USER.name()).isPresent();
409 boolean includeGroup = resource.getProvisionByAnyType(AnyTypeKind.GROUP.name()).isPresent();
410 boolean includeAnyObject = resource.getProvisions().stream().anyMatch(
411 provision -> !provision.getAnyType().equals(AnyTypeKind.USER.name())
412 && !provision.getAnyType().equals(AnyTypeKind.GROUP.name()));
413 boolean includeRealm = resource.getOrgUnit() != null;
414
415 if (includeUser) {
416 report.append("Users ").
417 append("[created/failures]: ").append(uSuccCreate.size()).append('/').append(uFailCreate.size()).
418 append(' ').
419 append("[updated/failures]: ").append(uSuccUpdate.size()).append('/').append(uFailUpdate.size()).
420 append(' ').
421 append("[deleted/failures]: ").append(uSuccDelete.size()).append('/').append(uFailDelete.size()).
422 append(' ').
423 append("[no operation/ignored]: ").append(uSuccNone.size()).append('/').append(uIgnore.size()).
424 append('\n');
425
426 report.append("Accounts ").
427 append("[created/failures]: ").append(laSuccCreate.size()).append('/').append(laFailCreate.size()).
428 append(' ').
429 append("[updated/failures]: ").append(laSuccUpdate.size()).append('/').append(laFailUpdate.size()).
430 append(' ').
431 append("[deleted/failures]: ").append(laSuccDelete.size()).append('/').append(laFailDelete.size()).
432 append(' ').
433 append("[no operation/ignored]: ").append(laSuccNone.size()).append('/').append(laIgnore.size()).
434 append('\n');
435 }
436 if (includeGroup) {
437 report.append("Groups ").
438 append("[created/failures]: ").append(gSuccCreate.size()).append('/').append(gFailCreate.size()).
439 append(' ').
440 append("[updated/failures]: ").append(gSuccUpdate.size()).append('/').append(gFailUpdate.size()).
441 append(' ').
442 append("[deleted/failures]: ").append(gSuccDelete.size()).append('/').append(gFailDelete.size()).
443 append(' ').
444 append("[no operation/ignored]: ").append(gSuccNone.size()).append('/').append(gIgnore.size()).
445 append('\n');
446 }
447 if (includeAnyObject) {
448 report.append("Any objects ").
449 append("[created/failures]: ").append(aSuccCreate.size()).append('/').append(aFailCreate.size()).
450 append(' ').
451 append("[updated/failures]: ").append(aSuccUpdate.size()).append('/').append(aFailUpdate.size()).
452 append(' ').
453 append("[deleted/failures]: ").append(aSuccDelete.size()).append('/').append(aFailDelete.size()).
454 append(' ').
455 append("[no operation/ignored]: ").append(aSuccNone.size()).append('/').append(aIgnore.size());
456 }
457 if (includeRealm) {
458 report.append("Realms ").
459 append("[created/failures]: ").append(rSuccCreate.size()).append('/').append(rFailCreate.size()).
460 append(' ').
461 append("[updated/failures]: ").append(rSuccUpdate.size()).append('/').append(rFailUpdate.size()).
462 append(' ').
463 append("[deleted/failures]: ").append(rSuccDelete.size()).append('/').append(rFailDelete.size()).
464 append(' ').
465 append("[no operation/ignored]: ").append(rSuccNone.size()).append('/').append(rIgnore.size());
466 }
467
468
469 if (traceLevel == TraceLevel.FAILURES || traceLevel == TraceLevel.ALL) {
470 if (includeUser) {
471 if (!uFailCreate.isEmpty()) {
472 report.append("\n\nUsers failed to create: ");
473 report.append(generate(uFailCreate, traceLevel));
474 }
475 if (!uFailUpdate.isEmpty()) {
476 report.append("\nUsers failed to update: ");
477 report.append(generate(uFailUpdate, traceLevel));
478 }
479 if (!uFailDelete.isEmpty()) {
480 report.append("\nUsers failed to delete: ");
481 report.append(generate(uFailDelete, traceLevel));
482 }
483
484 if (!laFailCreate.isEmpty()) {
485 report.append("\n\nAccounts failed to create: ");
486 report.append(generate(laFailCreate, traceLevel));
487 }
488 if (!laFailUpdate.isEmpty()) {
489 report.append("\nAccounts failed to update: ");
490 report.append(generate(laFailUpdate, traceLevel));
491 }
492 if (!laFailDelete.isEmpty()) {
493 report.append("\nAccounts failed to delete: ");
494 report.append(generate(laFailDelete, traceLevel));
495 }
496 }
497
498 if (includeGroup) {
499 if (!gFailCreate.isEmpty()) {
500 report.append("\n\nGroups failed to create: ");
501 report.append(generate(gFailCreate, traceLevel));
502 }
503 if (!gFailUpdate.isEmpty()) {
504 report.append("\nGroups failed to update: ");
505 report.append(generate(gFailUpdate, traceLevel));
506 }
507 if (!gFailDelete.isEmpty()) {
508 report.append("\nGroups failed to delete: ");
509 report.append(generate(gFailDelete, traceLevel));
510 }
511 }
512
513 if (includeAnyObject && !aFailCreate.isEmpty()) {
514 report.append("\nAny objects failed to create: ");
515 report.append(generate(aFailCreate, traceLevel));
516 }
517 if (includeAnyObject && !aFailUpdate.isEmpty()) {
518 report.append("\nAny objects failed to update: ");
519 report.append(generate(aFailUpdate, traceLevel));
520 }
521 if (includeAnyObject && !aFailDelete.isEmpty()) {
522 report.append("\nAny objects failed to delete: ");
523 report.append(generate(aFailDelete, traceLevel));
524 }
525
526 if (includeRealm) {
527 if (!rFailCreate.isEmpty()) {
528 report.append("\nRealms failed to create: ");
529 report.append(generate(rFailCreate, traceLevel));
530 }
531 if (!rFailUpdate.isEmpty()) {
532 report.append("\nRealms failed to update: ");
533 report.append(generate(rFailUpdate, traceLevel));
534 }
535 if (!rFailDelete.isEmpty()) {
536 report.append("\nRealms failed to delete: ");
537 report.append(generate(rFailDelete, traceLevel));
538 }
539 }
540 }
541
542
543 if (traceLevel == TraceLevel.ALL) {
544 if (includeUser) {
545 if (!uSuccCreate.isEmpty()) {
546 report.append("\n\nUsers created:\n").
547 append(generate(uSuccCreate, traceLevel));
548 }
549 if (!uSuccUpdate.isEmpty()) {
550 report.append("\nUsers updated:\n").
551 append(generate(uSuccUpdate, traceLevel));
552 }
553 if (!uSuccDelete.isEmpty()) {
554 report.append("\nUsers deleted:\n").
555 append(generate(uSuccDelete, traceLevel));
556 }
557 if (!uSuccNone.isEmpty()) {
558 report.append("\nUsers no operation:\n").
559 append(generate(uSuccNone, traceLevel));
560 }
561 if (!uIgnore.isEmpty()) {
562 report.append("\nUsers ignored:\n").
563 append(generate(uIgnore, traceLevel));
564 }
565
566 if (!laSuccCreate.isEmpty()) {
567 report.append("\n\nAccounts created:\n").
568 append(generate(laSuccCreate, traceLevel));
569 }
570 if (!laSuccUpdate.isEmpty()) {
571 report.append("\nAccounts updated:\n").
572 append(generate(laSuccUpdate, traceLevel));
573 }
574 if (!laSuccDelete.isEmpty()) {
575 report.append("\nAccounts deleted:\n").
576 append(generate(laSuccDelete, traceLevel));
577 }
578 if (!laSuccNone.isEmpty()) {
579 report.append("\nAccounts no operation:\n").
580 append(generate(laSuccNone, traceLevel));
581 }
582 if (!laIgnore.isEmpty()) {
583 report.append("\nAccounts ignored:\n").
584 append(generate(laIgnore, traceLevel));
585 }
586 }
587 if (includeGroup) {
588 if (!gSuccCreate.isEmpty()) {
589 report.append("\n\nGroups created:\n").
590 append(generate(gSuccCreate, traceLevel));
591 }
592 if (!gSuccUpdate.isEmpty()) {
593 report.append("\nGroups updated:\n").
594 append(generate(gSuccUpdate, traceLevel));
595 }
596 if (!gSuccDelete.isEmpty()) {
597 report.append("\nGroups deleted:\n").
598 append(generate(gSuccDelete, traceLevel));
599 }
600 if (!gSuccNone.isEmpty()) {
601 report.append("\nGroups no operation:\n").
602 append(generate(gSuccNone, traceLevel));
603 }
604 if (!gIgnore.isEmpty()) {
605 report.append("\nGroups ignored:\n").
606 append(generate(gIgnore, traceLevel));
607 }
608 }
609 if (includeAnyObject) {
610 if (!aSuccCreate.isEmpty()) {
611 report.append("\n\nAny objects created:\n").
612 append(generate(aSuccCreate, traceLevel));
613 }
614 if (!aSuccUpdate.isEmpty()) {
615 report.append("\nAny objects updated:\n").
616 append(generate(aSuccUpdate, traceLevel));
617 }
618 if (!aSuccDelete.isEmpty()) {
619 report.append("\nAny objects deleted:\n").
620 append(generate(aSuccDelete, traceLevel));
621 }
622 if (!aSuccNone.isEmpty()) {
623 report.append("\nAny objects no operation:\n").
624 append(generate(aSuccNone, traceLevel));
625 }
626 if (!aIgnore.isEmpty()) {
627 report.append("\nAny objects ignored:\n").
628 append(generate(aIgnore, traceLevel));
629 }
630 }
631 if (includeRealm) {
632 if (!rSuccCreate.isEmpty()) {
633 report.append("\n\nRealms created:\n").
634 append(generate(rSuccCreate, traceLevel));
635 }
636 if (!rSuccUpdate.isEmpty()) {
637 report.append("\nRealms updated:\n").
638 append(generate(rSuccUpdate, traceLevel));
639 }
640 if (!rSuccDelete.isEmpty()) {
641 report.append("\nRealms deleted:\n").
642 append(generate(rSuccDelete, traceLevel));
643 }
644 if (!rSuccNone.isEmpty()) {
645 report.append("\nRealms no operation:\n").
646 append(generate(rSuccNone, traceLevel));
647 }
648 if (!rIgnore.isEmpty()) {
649 report.append("\nRealms ignored:\n").
650 append(generate(rIgnore, traceLevel));
651 }
652 }
653 }
654
655 return report.toString();
656 }
657
658 protected Connector getConnector(final T provisioningTask) throws JobExecutionException {
659 Connector connector;
660 try {
661 connector = connectorManager.getConnector(provisioningTask.getResource());
662 } catch (Exception e) {
663 String msg = String.format("Connector instance bean for resource %s and connInstance %s not found",
664 provisioningTask.getResource(), provisioningTask.getResource().getConnector());
665 throw new JobExecutionException(msg, e);
666 }
667
668 return connector;
669 }
670
671 @Override
672 protected String doExecute(final boolean dryRun, final String executor, final JobExecutionContext context)
673 throws JobExecutionException {
674
675 try {
676 Class<T> clazz = getTaskClassReference();
677 if (!clazz.isAssignableFrom(task.getClass())) {
678 throw new JobExecutionException("Task " + task.getKey() + " isn't a ProvisioningTask");
679 }
680
681 T provisioningTask = clazz.cast(task);
682
683 Connector connector = getConnector(provisioningTask);
684
685 boolean noMapping = true;
686 for (Provision provision : provisioningTask.getResource().getProvisions()) {
687 Mapping mapping = provision.getMapping();
688 if (mapping != null) {
689 noMapping = false;
690 if (mapping.getConnObjectKeyItem() == null) {
691 throw new JobExecutionException("Invalid ConnObjectKey mapping for provision " + provision);
692 }
693 }
694 }
695 if (noMapping) {
696 noMapping = provisioningTask.getResource().getOrgUnit() == null;
697 }
698 if (noMapping) {
699 return "No provisions nor orgUnit available: aborting...";
700 }
701
702 return doExecuteProvisioning(provisioningTask, connector, dryRun, executor, context);
703 } catch (Throwable t) {
704 LOG.error("While executing provisioning job {}", getClass().getName(), t);
705 throw t;
706 }
707 }
708
709 protected abstract String doExecuteProvisioning(
710 T task, Connector connector, boolean dryRun, String executor, JobExecutionContext context)
711 throws JobExecutionException;
712
713 @Override
714 protected boolean hasToBeRegistered(final TaskExec<?> execution) {
715
716 return (TaskJob.Status.valueOf(execution.getStatus()) == TaskJob.Status.FAILURE
717 && task.getResource().getProvisioningTraceLevel().ordinal() >= TraceLevel.FAILURES.ordinal())
718 || task.getResource().getProvisioningTraceLevel().ordinal() >= TraceLevel.SUMMARY.ordinal();
719 }
720
721 @SuppressWarnings("unchecked")
722 protected Class<T> getTaskClassReference() {
723 return (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
724 }
725 }