001/* 002 * Copyright 2008-2020 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2008-2020 Ping Identity Corporation 007 * 008 * Licensed under the Apache License, Version 2.0 (the "License"); 009 * you may not use this file except in compliance with the License. 010 * You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, software 015 * distributed under the License is distributed on an "AS IS" BASIS, 016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 017 * See the License for the specific language governing permissions and 018 * limitations under the License. 019 */ 020/* 021 * Copyright (C) 2008-2020 Ping Identity Corporation 022 * 023 * This program is free software; you can redistribute it and/or modify 024 * it under the terms of the GNU General Public License (GPLv2 only) 025 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 026 * as published by the Free Software Foundation. 027 * 028 * This program is distributed in the hope that it will be useful, 029 * but WITHOUT ANY WARRANTY; without even the implied warranty of 030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 031 * GNU General Public License for more details. 032 * 033 * You should have received a copy of the GNU General Public License 034 * along with this program; if not, see <http://www.gnu.org/licenses>. 035 */ 036package com.unboundid.ldap.sdk.unboundidds.tasks; 037 038 039 040import java.io.Serializable; 041import java.text.ParseException; 042import java.util.ArrayList; 043import java.util.Arrays; 044import java.util.Collections; 045import java.util.Date; 046import java.util.Iterator; 047import java.util.LinkedHashMap; 048import java.util.List; 049import java.util.Map; 050import java.util.UUID; 051 052import com.unboundid.ldap.sdk.Attribute; 053import com.unboundid.ldap.sdk.Entry; 054import com.unboundid.util.Debug; 055import com.unboundid.util.NotExtensible; 056import com.unboundid.util.NotNull; 057import com.unboundid.util.Nullable; 058import com.unboundid.util.StaticUtils; 059import com.unboundid.util.ThreadSafety; 060import com.unboundid.util.ThreadSafetyLevel; 061import com.unboundid.util.Validator; 062 063import static com.unboundid.ldap.sdk.unboundidds.tasks.TaskMessages.*; 064 065 066 067/** 068 * This class defines a data structure for holding information about scheduled 069 * tasks as used by the Ping Identity, UnboundID, or Nokia/Alcatel-Lucent 8661 070 * Directory Server. Subclasses will be used to provide additional 071 * functionality when dealing with certain types of tasks. 072 * <BR> 073 * <BLOCKQUOTE> 074 * <B>NOTE:</B> This class, and other classes within the 075 * {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only 076 * supported for use against Ping Identity, UnboundID, and 077 * Nokia/Alcatel-Lucent 8661 server products. These classes provide support 078 * for proprietary functionality or for external specifications that are not 079 * considered stable or mature enough to be guaranteed to work in an 080 * interoperable way with other types of LDAP servers. 081 * </BLOCKQUOTE> 082 * <BR> 083 * All types of tasks can include the following information: 084 * <UL> 085 * <LI>Task ID -- Uniquely identifies the task in the server. It may be 086 * omitted when scheduling a new task in order to have a task ID generated 087 * for the task.</LI> 088 * <LI>Task Class Name -- The fully-qualified name of the {@code Task} 089 * subclass that provides the logic for the task. This does not need to 090 * be provided when creating a new task from one of the task-specific 091 * subclasses.</LI> 092 * <LI>Task State -- The current state of the task. See the {@link TaskState} 093 * enum for information about the possible states that a task may 094 * have.</LI> 095 * <LI>Scheduled Start Time -- The earliest time that the task should be 096 * eligible to start. It may be omitted when scheduling a new task in 097 * order to use the current time.</LI> 098 * <LI>Actual Start Time -- The time that server started processing the 099 * task.</LI> 100 * <LI>Actual Start Time -- The time that server completed processing for the 101 * task.</LI> 102 * <LI>Dependency IDs -- A list of task IDs for tasks that must complete 103 * before this task may be considered eligible to start.</LI> 104 * <LI>Failed Dependency Action -- Specifies how the server should treat this 105 * task if any of the tasks on which it depends failed. See the 106 * {@link FailedDependencyAction} enum for the failed dependency action 107 * values that may be used.</LI> 108 * <LI>Notify on Completion -- A list of e-mail addresses for users that 109 * should be notified when the task completes, regardless of whether it 110 * was successful.</LI> 111 * <LI>Notify On Error -- A list of e-mail addresses for users that should be 112 * notified if the task fails.</LI> 113 * <LI>Log Messages -- A list of the messages logged by the task while it was 114 * running.</LI> 115 * </UL> 116 * Each of these elements can be retrieving using specific methods within this 117 * class (e.g., the {@link Task#getTaskID} method can be used to retrieve the 118 * task ID), but task properties (including those specific to the particular 119 * type to task) may also be accessed using a generic API. For example, the 120 * {@link Task#getTaskPropertyValues} method retrieves a map that correlates the 121 * {@link TaskProperty} objects for the task with the values that have been set 122 * for those properties. See the documentation for the {@link TaskManager} 123 * class for an example that demonstrates accessing task information using the 124 * generic API. 125 * <BR><BR> 126 * Also note that it is possible to create new tasks using information obtained 127 * from the generic API, but that is done on a per-class basis. For example, in 128 * order to create a new {@link BackupTask} instance using the generic API, you 129 * would use the {@link BackupTask#BackupTask(Map)} constructor, in which the 130 * provided map contains a mapping between the properties and their values for 131 * that task. The {@link Task#getTaskSpecificProperties} method may be used to 132 * retrieve a list of the task-specific properties that may be provided when 133 * scheduling a task, and the {@link Task#getCommonTaskProperties} method may be 134 * used to retrieve a list of properties that can be provided when scheduling 135 * any type of task. 136 */ 137@NotExtensible() 138@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 139public class Task 140 implements Serializable 141{ 142 /** 143 * The name of the attribute used to hold the actual start time for scheduled 144 * tasks. 145 */ 146 @NotNull private static final String ATTR_ACTUAL_START_TIME = 147 "ds-task-actual-start-time"; 148 149 150 151 /** 152 * The name of the attribute used to indicate whether the server should 153 * generate an administrative alert when the task fails to complete 154 * successfully. 155 */ 156 @NotNull private static final String ATTR_ALERT_ON_ERROR = 157 "ds-task-alert-on-error"; 158 159 160 161 /** 162 * The name of the attribute used to indicate whether the server should 163 * generate an administrative alert when the task starts running. 164 */ 165 @NotNull private static final String ATTR_ALERT_ON_START = 166 "ds-task-alert-on-start"; 167 168 169 170 /** 171 * The name of the attribute used to indicate whether the server should 172 * generate an administrative alert when the task completes successfully. 173 */ 174 @NotNull private static final String ATTR_ALERT_ON_SUCCESS = 175 "ds-task-alert-on-success"; 176 177 178 179 /** 180 * The name of the attribute used to hold the completion time for scheduled 181 * tasks. 182 */ 183 @NotNull private static final String ATTR_COMPLETION_TIME = 184 "ds-task-completion-time"; 185 186 187 188 /** 189 * The name of the attribute used to hold the task IDs for tasks on which a 190 * scheduled task is dependent. 191 */ 192 @NotNull private static final String ATTR_DEPENDENCY_ID = 193 "ds-task-dependency-id"; 194 195 196 197 /** 198 * The name of the attribute used to indicate what action to take if one of 199 * the dependencies for a task failed to complete successfully. 200 */ 201 @NotNull private static final String ATTR_FAILED_DEPENDENCY_ACTION = 202 "ds-task-failed-dependency-action"; 203 204 205 206 /** 207 * The name of the attribute used to hold the log messages for scheduled 208 * tasks. 209 */ 210 @NotNull private static final String ATTR_LOG_MESSAGE = "ds-task-log-message"; 211 212 213 214 /** 215 * The name of the attribute used to hold the e-mail addresses of the users 216 * that should be notified whenever a scheduled task completes, regardless of 217 * success or failure. 218 */ 219 @NotNull private static final String ATTR_NOTIFY_ON_COMPLETION = 220 "ds-task-notify-on-completion"; 221 222 223 224 /** 225 * The name of the attribute used to hold the e-mail addresses of the users 226 * that should be notified if a scheduled task fails to complete successfully. 227 */ 228 @NotNull private static final String ATTR_NOTIFY_ON_ERROR = 229 "ds-task-notify-on-error"; 230 231 232 233 /** 234 * The name of the attribute used to hold the e-mail addresses of the users 235 * that should be notified when a scheduled task starts running. 236 */ 237 @NotNull private static final String ATTR_NOTIFY_ON_START = 238 "ds-task-notify-on-start"; 239 240 241 242 /** 243 * The name of the attribute used to hold the e-mail addresses of the users 244 * that should be notified when a scheduled task completes successfully. 245 */ 246 @NotNull private static final String ATTR_NOTIFY_ON_SUCCESS = 247 "ds-task-notify-on-success"; 248 249 250 251 /** 252 * The name of the attribute used to hold the scheduled start time for 253 * scheduled tasks. 254 */ 255 @NotNull private static final String ATTR_SCHEDULED_START_TIME = 256 "ds-task-scheduled-start-time"; 257 258 259 260 /** 261 * The name of the attribute used to hold the name of the class that provides 262 * the logic for scheduled tasks. 263 */ 264 @NotNull private static final String ATTR_TASK_CLASS = "ds-task-class-name"; 265 266 267 268 /** 269 * The name of the attribute used to hold the task ID for scheduled tasks. 270 */ 271 @NotNull static final String ATTR_TASK_ID = "ds-task-id"; 272 273 274 275 /** 276 * The name of the attribute used to hold the current state for scheduled 277 * tasks. 278 */ 279 @NotNull static final String ATTR_TASK_STATE = "ds-task-state"; 280 281 282 283 /** 284 * The name of the base object class for scheduled tasks. 285 */ 286 @NotNull static final String OC_TASK = "ds-task"; 287 288 289 290 /** 291 * The DN of the entry below which scheduled tasks reside. 292 */ 293 @NotNull static final String SCHEDULED_TASKS_BASE_DN = 294 "cn=Scheduled Tasks,cn=tasks"; 295 296 297 298 /** 299 * The task property that will be used for the task ID. 300 */ 301 @NotNull private static final TaskProperty PROPERTY_TASK_ID = 302 new TaskProperty(ATTR_TASK_ID, INFO_DISPLAY_NAME_TASK_ID.get(), 303 INFO_DESCRIPTION_TASK_ID.get(), String.class, false, 304 false, true); 305 306 307 308 /** 309 * The task property that will be used for the scheduled start time. 310 */ 311 @NotNull private static final TaskProperty PROPERTY_SCHEDULED_START_TIME = 312 new TaskProperty(ATTR_SCHEDULED_START_TIME, 313 INFO_DISPLAY_NAME_SCHEDULED_START_TIME.get(), 314 INFO_DESCRIPTION_SCHEDULED_START_TIME.get(), Date.class, 315 false, false, true); 316 317 318 319 /** 320 * The task property that will be used for the set of dependency IDs. 321 */ 322 @NotNull private static final TaskProperty PROPERTY_DEPENDENCY_ID = 323 new TaskProperty(ATTR_DEPENDENCY_ID, 324 INFO_DISPLAY_NAME_DEPENDENCY_ID.get(), 325 INFO_DESCRIPTION_DEPENDENCY_ID.get(), String.class, 326 false, true, true); 327 328 329 330 /** 331 * The task property that will be used for the failed dependency action. 332 */ 333 @NotNull private static final TaskProperty PROPERTY_FAILED_DEPENDENCY_ACTION = 334 new TaskProperty(ATTR_FAILED_DEPENDENCY_ACTION, 335 INFO_DISPLAY_NAME_FAILED_DEPENDENCY_ACTION.get(), 336 INFO_DESCRIPTION_FAILED_DEPENDENCY_ACTION.get(), 337 String.class, false, false, true, 338 new String[] 339 { 340 FailedDependencyAction.CANCEL.getName(), 341 FailedDependencyAction.DISABLE.getName(), 342 FailedDependencyAction.PROCESS.getName() 343 }); 344 345 346 347 /** 348 * The task property that will be used for the notify on completion addresses. 349 */ 350 @NotNull private static final TaskProperty PROPERTY_NOTIFY_ON_COMPLETION = 351 new TaskProperty(ATTR_NOTIFY_ON_COMPLETION, 352 INFO_DISPLAY_NAME_NOTIFY_ON_COMPLETION.get(), 353 INFO_DESCRIPTION_NOTIFY_ON_COMPLETION.get(), 354 String.class, false, true, true); 355 356 357 358 /** 359 * The task property that will be used for the notify on error addresses. 360 */ 361 @NotNull private static final TaskProperty PROPERTY_NOTIFY_ON_ERROR = 362 new TaskProperty(ATTR_NOTIFY_ON_ERROR, 363 INFO_DISPLAY_NAME_NOTIFY_ON_ERROR.get(), 364 INFO_DESCRIPTION_NOTIFY_ON_ERROR.get(), 365 String.class, false, true, true); 366 367 368 369 /** 370 * The task property that will be used for the notify on success addresses. 371 */ 372 @NotNull private static final TaskProperty PROPERTY_NOTIFY_ON_SUCCESS = 373 new TaskProperty(ATTR_NOTIFY_ON_SUCCESS, 374 INFO_DISPLAY_NAME_NOTIFY_ON_SUCCESS.get(), 375 INFO_DESCRIPTION_NOTIFY_ON_SUCCESS.get(), 376 String.class, false, true, true); 377 378 379 380 /** 381 * The task property that will be used for the notify on start addresses. 382 */ 383 @NotNull private static final TaskProperty PROPERTY_NOTIFY_ON_START = 384 new TaskProperty(ATTR_NOTIFY_ON_START, 385 INFO_DISPLAY_NAME_NOTIFY_ON_START.get(), 386 INFO_DESCRIPTION_NOTIFY_ON_START.get(), 387 String.class, false, true, true); 388 389 390 391 /** 392 * The task property that will be used for the alert on error flag. 393 */ 394 @NotNull private static final TaskProperty PROPERTY_ALERT_ON_ERROR = 395 new TaskProperty(ATTR_ALERT_ON_ERROR, 396 INFO_DISPLAY_NAME_ALERT_ON_ERROR.get(), 397 INFO_DESCRIPTION_ALERT_ON_ERROR.get(), 398 Boolean.class, false, false, true); 399 400 401 402 /** 403 * The task property that will be used for the alert on start flag. 404 */ 405 @NotNull private static final TaskProperty PROPERTY_ALERT_ON_START = 406 new TaskProperty(ATTR_ALERT_ON_START, 407 INFO_DISPLAY_NAME_ALERT_ON_START.get(), 408 INFO_DESCRIPTION_ALERT_ON_START.get(), 409 Boolean.class, false, false, true); 410 411 412 413 /** 414 * The task property that will be used for the alert on success flag. 415 */ 416 @NotNull private static final TaskProperty PROPERTY_ALERT_ON_SUCCESS = 417 new TaskProperty(ATTR_ALERT_ON_SUCCESS, 418 INFO_DISPLAY_NAME_ALERT_ON_SUCCESS.get(), 419 INFO_DESCRIPTION_ALERT_ON_SUCCESS.get(), 420 Boolean.class, false, false, true); 421 422 423 424 /** 425 * The serial version UID for this serializable class. 426 */ 427 private static final long serialVersionUID = -4082350090081577623L; 428 429 430 431 // Indicates whether to generate an administrative alert when the task fails 432 // to complete successfully. 433 @Nullable private final Boolean alertOnError; 434 435 // Indicates whether to generate an administrative alert when the task starts. 436 @Nullable private final Boolean alertOnStart; 437 438 // Indicates whether to generate an administrative alert when the task 439 // completes successfully. 440 @Nullable private final Boolean alertOnSuccess; 441 442 // The time that this task actually started. 443 @Nullable private final Date actualStartTime; 444 445 // The time that this task completed. 446 @Nullable private final Date completionTime; 447 448 // The time that this task was scheduled to start. 449 @Nullable private final Date scheduledStartTime; 450 451 // The entry from which this task was decoded. 452 @Nullable private final Entry taskEntry; 453 454 // The failed dependency action for this task. 455 @Nullable private final FailedDependencyAction failedDependencyAction; 456 457 // The set of task IDs of the tasks on which this task is dependent. 458 @NotNull private final List<String> dependencyIDs; 459 460 // The set of log messages for this task. 461 @NotNull private final List<String> logMessages; 462 463 // The set of e-mail addresses of users that should be notified when the task 464 // processing is complete. 465 @NotNull private final List<String> notifyOnCompletion; 466 467 // The set of e-mail addresses of users that should be notified if task 468 // processing completes with an error. 469 @NotNull private final List<String> notifyOnError; 470 471 // The set of e-mail addresses of users that should be notified if task 472 // processing starts. 473 @NotNull private final List<String> notifyOnStart; 474 475 // The set of e-mail addresses of users that should be notified if task 476 // processing completes successfully. 477 @NotNull private final List<String> notifyOnSuccess; 478 479 // The fully-qualified name of the task class. 480 @NotNull private final String taskClassName; 481 482 // The DN of the entry for this task. 483 @NotNull private final String taskEntryDN; 484 485 // The task ID for this task. 486 @NotNull private final String taskID; 487 488 // The current state for this task. 489 @NotNull private final TaskState taskState; 490 491 492 493 /** 494 * Creates a new uninitialized task instance which should only be used for 495 * obtaining general information about this task, including the task name, 496 * description, and supported properties. Attempts to use a task created with 497 * this constructor for any other reason will likely fail. 498 */ 499 protected Task() 500 { 501 alertOnError = null; 502 alertOnStart = null; 503 alertOnSuccess = null; 504 actualStartTime = null; 505 completionTime = null; 506 scheduledStartTime = null; 507 taskEntry = null; 508 failedDependencyAction = null; 509 dependencyIDs = null; 510 logMessages = null; 511 notifyOnCompletion = null; 512 notifyOnError = null; 513 notifyOnStart = null; 514 notifyOnSuccess = null; 515 taskClassName = null; 516 taskEntryDN = null; 517 taskID = null; 518 taskState = null; 519 } 520 521 522 523 /** 524 * Creates a new unscheduled task with the specified task ID and class name. 525 * 526 * @param taskID The task ID to use for this task. If it is 527 * {@code null} then a UUID will be generated for use 528 * as the task ID. 529 * @param taskClassName The fully-qualified name of the Java class that 530 * provides the logic for the task. It must not be 531 * {@code null}. 532 */ 533 public Task(@Nullable final String taskID, 534 @NotNull final String taskClassName) 535 { 536 this(taskID, taskClassName, null, null, null, null, null); 537 } 538 539 540 541 /** 542 * Creates a new unscheduled task with the provided information. 543 * 544 * @param taskID The task ID to use for this task. 545 * @param taskClassName The fully-qualified name of the Java class 546 * that provides the logic for the task. It 547 * must not be {@code null}. 548 * @param scheduledStartTime The time that this task should start 549 * running. 550 * @param dependencyIDs The list of task IDs that will be required 551 * to complete before this task will be 552 * eligible to start. 553 * @param failedDependencyAction Indicates what action should be taken if 554 * any of the dependencies for this task do 555 * not complete successfully. 556 * @param notifyOnCompletion The list of e-mail addresses of individuals 557 * that should be notified when this task 558 * completes. 559 * @param notifyOnError The list of e-mail addresses of individuals 560 * that should be notified if this task does 561 * not complete successfully. 562 */ 563 public Task(@Nullable final String taskID, 564 @NotNull final String taskClassName, 565 @Nullable final Date scheduledStartTime, 566 @Nullable final List<String> dependencyIDs, 567 @Nullable final FailedDependencyAction failedDependencyAction, 568 @Nullable final List<String> notifyOnCompletion, 569 @Nullable final List<String> notifyOnError) 570 { 571 this(taskID, taskClassName, scheduledStartTime, dependencyIDs, 572 failedDependencyAction, null, notifyOnCompletion, null, 573 notifyOnError, null, null, null); 574 } 575 576 577 578 /** 579 * Creates a new unscheduled task with the provided information. 580 * 581 * @param taskID The task ID to use for this task. 582 * @param taskClassName The fully-qualified name of the Java class 583 * that provides the logic for the task. It 584 * must not be {@code null}. 585 * @param scheduledStartTime The time that this task should start 586 * running. 587 * @param dependencyIDs The list of task IDs that will be required 588 * to complete before this task will be 589 * eligible to start. 590 * @param failedDependencyAction Indicates what action should be taken if 591 * any of the dependencies for this task do 592 * not complete successfully. 593 * @param notifyOnStart The list of e-mail addresses of individuals 594 * that should be notified when this task 595 * starts running. 596 * @param notifyOnCompletion The list of e-mail addresses of individuals 597 * that should be notified when this task 598 * completes. 599 * @param notifyOnSuccess The list of e-mail addresses of individuals 600 * that should be notified if this task 601 * completes successfully. 602 * @param notifyOnError The list of e-mail addresses of individuals 603 * that should be notified if this task does 604 * not complete successfully. 605 * @param alertOnStart Indicates whether the server should send an 606 * alert notification when this task starts. 607 * @param alertOnSuccess Indicates whether the server should send an 608 * alert notification if this task completes 609 * successfully. 610 * @param alertOnError Indicates whether the server should send an 611 * alert notification if this task fails to 612 * complete successfully. 613 */ 614 public Task(@Nullable final String taskID, 615 @NotNull final String taskClassName, 616 @Nullable final Date scheduledStartTime, 617 @Nullable final List<String> dependencyIDs, 618 @Nullable final FailedDependencyAction failedDependencyAction, 619 @Nullable final List<String> notifyOnStart, 620 @Nullable final List<String> notifyOnCompletion, 621 @Nullable final List<String> notifyOnSuccess, 622 @Nullable final List<String> notifyOnError, 623 @Nullable final Boolean alertOnStart, 624 @Nullable final Boolean alertOnSuccess, 625 @Nullable final Boolean alertOnError) 626 { 627 Validator.ensureNotNull(taskClassName); 628 629 this.taskClassName = taskClassName; 630 this.scheduledStartTime = scheduledStartTime; 631 this.failedDependencyAction = failedDependencyAction; 632 this.alertOnStart = alertOnStart; 633 this.alertOnSuccess = alertOnSuccess; 634 this.alertOnError = alertOnError; 635 636 if (taskID == null) 637 { 638 this.taskID = UUID.randomUUID().toString(); 639 } 640 else 641 { 642 this.taskID = taskID; 643 } 644 645 if (dependencyIDs == null) 646 { 647 this.dependencyIDs = Collections.emptyList(); 648 } 649 else 650 { 651 this.dependencyIDs = Collections.unmodifiableList(dependencyIDs); 652 } 653 654 if (notifyOnStart == null) 655 { 656 this.notifyOnStart = Collections.emptyList(); 657 } 658 else 659 { 660 this.notifyOnStart = 661 Collections.unmodifiableList(notifyOnStart); 662 } 663 664 if (notifyOnCompletion == null) 665 { 666 this.notifyOnCompletion = Collections.emptyList(); 667 } 668 else 669 { 670 this.notifyOnCompletion = 671 Collections.unmodifiableList(notifyOnCompletion); 672 } 673 674 if (notifyOnSuccess == null) 675 { 676 this.notifyOnSuccess = Collections.emptyList(); 677 } 678 else 679 { 680 this.notifyOnSuccess = Collections.unmodifiableList(notifyOnSuccess); 681 } 682 683 if (notifyOnError == null) 684 { 685 this.notifyOnError = Collections.emptyList(); 686 } 687 else 688 { 689 this.notifyOnError = Collections.unmodifiableList(notifyOnError); 690 } 691 692 taskEntry = null; 693 taskEntryDN = ATTR_TASK_ID + '=' + this.taskID + ',' + 694 SCHEDULED_TASKS_BASE_DN; 695 actualStartTime = null; 696 completionTime = null; 697 logMessages = Collections.emptyList(); 698 taskState = TaskState.UNSCHEDULED; 699 } 700 701 702 703 /** 704 * Creates a new task from the provided entry. 705 * 706 * @param entry The entry to use to create this task. 707 * 708 * @throws TaskException If the provided entry cannot be parsed as a 709 * scheduled task. 710 */ 711 public Task(@NotNull final Entry entry) 712 throws TaskException 713 { 714 taskEntry = entry; 715 taskEntryDN = entry.getDN(); 716 717 // Ensure that the task entry has the appropriate object class for a 718 // scheduled task. 719 if (! entry.hasObjectClass(OC_TASK)) 720 { 721 throw new TaskException(ERR_TASK_MISSING_OC.get(taskEntryDN)); 722 } 723 724 725 // Get the task ID. It must be present. 726 taskID = entry.getAttributeValue(ATTR_TASK_ID); 727 if (taskID == null) 728 { 729 throw new TaskException(ERR_TASK_NO_ID.get(taskEntryDN)); 730 } 731 732 733 // Get the task class name. It must be present. 734 taskClassName = entry.getAttributeValue(ATTR_TASK_CLASS); 735 if (taskClassName == null) 736 { 737 throw new TaskException(ERR_TASK_NO_CLASS.get(taskEntryDN)); 738 } 739 740 741 // Get the task state. If it is not present, then assume "unscheduled". 742 final String stateStr = entry.getAttributeValue(ATTR_TASK_STATE); 743 if (stateStr == null) 744 { 745 taskState = TaskState.UNSCHEDULED; 746 } 747 else 748 { 749 taskState = TaskState.forName(stateStr); 750 if (taskState == null) 751 { 752 throw new TaskException(ERR_TASK_INVALID_STATE.get(taskEntryDN, 753 stateStr)); 754 } 755 } 756 757 758 // Get the scheduled start time. It may be absent. 759 String timestamp = entry.getAttributeValue(ATTR_SCHEDULED_START_TIME); 760 if (timestamp == null) 761 { 762 scheduledStartTime = null; 763 } 764 else 765 { 766 try 767 { 768 scheduledStartTime = StaticUtils.decodeGeneralizedTime(timestamp); 769 } 770 catch (final ParseException pe) 771 { 772 Debug.debugException(pe); 773 throw new TaskException(ERR_TASK_CANNOT_PARSE_SCHEDULED_START_TIME.get( 774 taskEntryDN, timestamp, pe.getMessage()), 775 pe); 776 } 777 } 778 779 780 // Get the actual start time. It may be absent. 781 timestamp = entry.getAttributeValue(ATTR_ACTUAL_START_TIME); 782 if (timestamp == null) 783 { 784 actualStartTime = null; 785 } 786 else 787 { 788 try 789 { 790 actualStartTime = StaticUtils.decodeGeneralizedTime(timestamp); 791 } 792 catch (final ParseException pe) 793 { 794 Debug.debugException(pe); 795 throw new TaskException(ERR_TASK_CANNOT_PARSE_ACTUAL_START_TIME.get( 796 taskEntryDN, timestamp, pe.getMessage()), 797 pe); 798 } 799 } 800 801 802 // Get the completion start time. It may be absent. 803 timestamp = entry.getAttributeValue(ATTR_COMPLETION_TIME); 804 if (timestamp == null) 805 { 806 completionTime = null; 807 } 808 else 809 { 810 try 811 { 812 completionTime = StaticUtils.decodeGeneralizedTime(timestamp); 813 } 814 catch (final ParseException pe) 815 { 816 Debug.debugException(pe); 817 throw new TaskException(ERR_TASK_CANNOT_PARSE_COMPLETION_TIME.get( 818 taskEntryDN, timestamp, pe.getMessage()), 819 pe); 820 } 821 } 822 823 824 // Get the failed dependency action for this task. It may be absent. 825 final String name = entry.getAttributeValue(ATTR_FAILED_DEPENDENCY_ACTION); 826 if (name == null) 827 { 828 failedDependencyAction = null; 829 } 830 else 831 { 832 failedDependencyAction = FailedDependencyAction.forName(name); 833 } 834 835 836 // Get the dependent task IDs for this task. It may be absent. 837 dependencyIDs = parseStringList(entry, ATTR_DEPENDENCY_ID); 838 839 840 // Get the log messages for this task. It may be absent. 841 logMessages = parseStringList(entry, ATTR_LOG_MESSAGE); 842 843 844 // Get the notify on start addresses for this task. It may be absent. 845 notifyOnStart = parseStringList(entry, ATTR_NOTIFY_ON_START); 846 847 848 // Get the notify on completion addresses for this task. It may be absent. 849 notifyOnCompletion = parseStringList(entry, ATTR_NOTIFY_ON_COMPLETION); 850 851 852 // Get the notify on success addresses for this task. It may be absent. 853 notifyOnSuccess = parseStringList(entry, ATTR_NOTIFY_ON_SUCCESS); 854 855 856 // Get the notify on error addresses for this task. It may be absent. 857 notifyOnError = parseStringList(entry, ATTR_NOTIFY_ON_ERROR); 858 859 860 // Get the alert on start flag for this task. It may be absent. 861 alertOnStart = entry.getAttributeValueAsBoolean(ATTR_ALERT_ON_START); 862 863 864 // Get the alert on success flag for this task. It may be absent. 865 alertOnSuccess = entry.getAttributeValueAsBoolean(ATTR_ALERT_ON_SUCCESS); 866 867 868 // Get the alert on error flag for this task. It may be absent. 869 alertOnError = entry.getAttributeValueAsBoolean(ATTR_ALERT_ON_ERROR); 870 } 871 872 873 874 /** 875 * Creates a new task from the provided set of task properties. 876 * 877 * @param taskClassName The fully-qualified name of the Java class that 878 * provides the logic for the task. It must not be 879 * {@code null}. 880 * @param properties The set of task properties and their corresponding 881 * values to use for the task. It must not be 882 * {@code null}. 883 * 884 * @throws TaskException If the provided set of properties cannot be used to 885 * create a valid scheduled task. 886 */ 887 public Task(@NotNull final String taskClassName, 888 @NotNull final Map<TaskProperty,List<Object>> properties) 889 throws TaskException 890 { 891 Validator.ensureNotNull(taskClassName, properties); 892 893 this.taskClassName = taskClassName; 894 895 String idStr = UUID.randomUUID().toString(); 896 Date sst = null; 897 String[] depIDs = StaticUtils.NO_STRINGS; 898 FailedDependencyAction fda = FailedDependencyAction.CANCEL; 899 String[] nob = StaticUtils.NO_STRINGS; 900 String[] noc = StaticUtils.NO_STRINGS; 901 String[] noe = StaticUtils.NO_STRINGS; 902 String[] nos = StaticUtils.NO_STRINGS; 903 Boolean aob = null; 904 Boolean aoe = null; 905 Boolean aos = null; 906 907 for (final Map.Entry<TaskProperty,List<Object>> entry : 908 properties.entrySet()) 909 { 910 final TaskProperty p = entry.getKey(); 911 final String attrName = p.getAttributeName(); 912 final List<Object> values = entry.getValue(); 913 914 if (attrName.equalsIgnoreCase(ATTR_TASK_ID)) 915 { 916 idStr = parseString(p, values, idStr); 917 } 918 else if (attrName.equalsIgnoreCase(ATTR_SCHEDULED_START_TIME)) 919 { 920 sst = parseDate(p, values, sst); 921 } 922 else if (attrName.equalsIgnoreCase(ATTR_DEPENDENCY_ID)) 923 { 924 depIDs = parseStrings(p, values, depIDs); 925 } 926 else if (attrName.equalsIgnoreCase(ATTR_FAILED_DEPENDENCY_ACTION)) 927 { 928 fda = FailedDependencyAction.forName( 929 parseString(p, values, fda.getName())); 930 } 931 else if (attrName.equalsIgnoreCase(ATTR_NOTIFY_ON_START)) 932 { 933 nob = parseStrings(p, values, nob); 934 } 935 else if (attrName.equalsIgnoreCase(ATTR_NOTIFY_ON_COMPLETION)) 936 { 937 noc = parseStrings(p, values, noc); 938 } 939 else if (attrName.equalsIgnoreCase(ATTR_NOTIFY_ON_SUCCESS)) 940 { 941 nos = parseStrings(p, values, nos); 942 } 943 else if (attrName.equalsIgnoreCase(ATTR_NOTIFY_ON_ERROR)) 944 { 945 noe = parseStrings(p, values, noe); 946 } 947 else if (attrName.equalsIgnoreCase(ATTR_ALERT_ON_START)) 948 { 949 aob = parseBoolean(p, values, aob); 950 } 951 else if (attrName.equalsIgnoreCase(ATTR_ALERT_ON_SUCCESS)) 952 { 953 aos = parseBoolean(p, values, aos); 954 } 955 else if (attrName.equalsIgnoreCase(ATTR_ALERT_ON_ERROR)) 956 { 957 aoe = parseBoolean(p, values, aoe); 958 } 959 } 960 961 taskID = idStr; 962 scheduledStartTime = sst; 963 dependencyIDs = Collections.unmodifiableList(Arrays.asList(depIDs)); 964 failedDependencyAction = fda; 965 notifyOnStart = Collections.unmodifiableList(Arrays.asList(nob)); 966 notifyOnCompletion = Collections.unmodifiableList(Arrays.asList(noc)); 967 notifyOnSuccess = Collections.unmodifiableList(Arrays.asList(nos)); 968 notifyOnError = Collections.unmodifiableList(Arrays.asList(noe)); 969 alertOnStart = aob; 970 alertOnSuccess = aos; 971 alertOnError = aoe; 972 taskEntry = null; 973 taskEntryDN = ATTR_TASK_ID + '=' + taskID + ',' + SCHEDULED_TASKS_BASE_DN; 974 actualStartTime = null; 975 completionTime = null; 976 logMessages = Collections.emptyList(); 977 taskState = TaskState.UNSCHEDULED; 978 } 979 980 981 982 /** 983 * Retrieves a list containing instances of the available task types. The 984 * provided task instances will may only be used for obtaining general 985 * information about the task (e.g., name, description, and supported 986 * properties). 987 * 988 * @return A list containing instances of the available task types. 989 */ 990 @NotNull() 991 public static List<Task> getAvailableTaskTypes() 992 { 993 final List<Task> taskList = Arrays.asList( 994 new AddSchemaFileTask(), 995 new AlertTask(), 996 new AuditDataSecurityTask(), 997 new BackupTask(), 998 new CollectSupportDataTask(), 999 new DelayTask(), 1000 new DisconnectClientTask(), 1001 new DumpDBDetailsTask(), 1002 new EnterLockdownModeTask(), 1003 new ExecTask(), 1004 new ExportTask(), 1005 new FileRetentionTask(), 1006 new GenerateServerProfileTask(), 1007 new GroovyScriptedTask(), 1008 new ImportTask(), 1009 new LeaveLockdownModeTask(), 1010 new PopulateComposedAttributeValuesTask(), 1011 new RebuildTask(), 1012 new ReEncodeEntriesTask(), 1013 new RefreshEncryptionSettingsTask(), 1014 new ReloadGlobalIndexTask(), 1015 new ReloadHTTPConnectionHandlerCertificatesTask(), 1016 new RestoreTask(), 1017 new RotateLogTask(), 1018 new SearchTask(), 1019 new ShutdownTask(), 1020 new SynchronizeEncryptionSettingsTask(), 1021 new ThirdPartyTask()); 1022 1023 return Collections.unmodifiableList(taskList); 1024 } 1025 1026 1027 1028 /** 1029 * Retrieves a human-readable name for this task. 1030 * 1031 * @return A human-readable name for this task. 1032 */ 1033 @NotNull() 1034 public String getTaskName() 1035 { 1036 return INFO_TASK_NAME_GENERIC.get(); 1037 } 1038 1039 1040 1041 /** 1042 * Retrieves a human-readable description for this task. 1043 * 1044 * @return A human-readable description for this task. 1045 */ 1046 @NotNull() 1047 public String getTaskDescription() 1048 { 1049 return INFO_TASK_DESCRIPTION_GENERIC.get(); 1050 } 1051 1052 1053 1054 /** 1055 * Retrieves the entry from which this task was decoded, if available. Note 1056 * that although the entry is not immutable, changes made to it will not be 1057 * reflected in this task. 1058 * 1059 * @return The entry from which this task was decoded, or {@code null} if 1060 * this task was not created from an existing entry. 1061 */ 1062 @Nullable() 1063 protected final Entry getTaskEntry() 1064 { 1065 return taskEntry; 1066 } 1067 1068 1069 1070 /** 1071 * Retrieves the DN of the entry in which this scheduled task is defined. 1072 * 1073 * @return The DN of the entry in which this scheduled task is defined. 1074 */ 1075 @NotNull() 1076 public final String getTaskEntryDN() 1077 { 1078 return taskEntryDN; 1079 } 1080 1081 1082 1083 /** 1084 * Retrieves the task ID for this task. 1085 * 1086 * @return The task ID for this task. 1087 */ 1088 @NotNull() 1089 public final String getTaskID() 1090 { 1091 return taskID; 1092 } 1093 1094 1095 1096 /** 1097 * Retrieves the fully-qualified name of the Java class that provides the 1098 * logic for this class. 1099 * 1100 * @return The fully-qualified name of the Java class that provides the logic 1101 * for this task. 1102 */ 1103 @NotNull() 1104 public final String getTaskClassName() 1105 { 1106 return taskClassName; 1107 } 1108 1109 1110 1111 /** 1112 * Retrieves the current state for this task. 1113 * 1114 * @return The current state for this task. 1115 */ 1116 @NotNull() 1117 public final TaskState getState() 1118 { 1119 return taskState; 1120 } 1121 1122 1123 1124 /** 1125 * Indicates whether this task is currently pending execution. 1126 * 1127 * @return {@code true} if this task is currently pending execution, or 1128 * {@code false} if not. 1129 */ 1130 public final boolean isPending() 1131 { 1132 return taskState.isPending(); 1133 } 1134 1135 1136 1137 /** 1138 * Indicates whether this task is currently running. 1139 * 1140 * @return {@code true} if this task is currently running, or {@code false} 1141 * if not. 1142 */ 1143 public final boolean isRunning() 1144 { 1145 return taskState.isRunning(); 1146 } 1147 1148 1149 1150 /** 1151 * Indicates whether this task has completed execution. 1152 * 1153 * @return {@code true} if this task has completed execution, or 1154 * {@code false} if not. 1155 */ 1156 public final boolean isCompleted() 1157 { 1158 return taskState.isCompleted(); 1159 } 1160 1161 1162 1163 /** 1164 * Retrieves the time that this task is/was scheduled to start running. 1165 * 1166 * @return The time that this task is/was scheduled to start running, or 1167 * {@code null} if that is not available and therefore the task 1168 * should start running as soon as all dependencies have been met. 1169 */ 1170 @Nullable() 1171 public final Date getScheduledStartTime() 1172 { 1173 return scheduledStartTime; 1174 } 1175 1176 1177 1178 /** 1179 * Retrieves the time that this task actually started running. 1180 * 1181 * @return The time that this task actually started running, or {@code null} 1182 * if that is not available (e.g., because the task has not yet 1183 * started). 1184 */ 1185 @Nullable() 1186 public final Date getActualStartTime() 1187 { 1188 return actualStartTime; 1189 } 1190 1191 1192 1193 /** 1194 * Retrieves the time that this task completed. 1195 * 1196 * @return The time that this task completed, or {@code null} if it has not 1197 * yet completed. 1198 */ 1199 @Nullable() 1200 public final Date getCompletionTime() 1201 { 1202 return completionTime; 1203 } 1204 1205 1206 1207 /** 1208 * Retrieves a list of the task IDs for tasks that must complete before this 1209 * task will be eligible to start. 1210 * 1211 * @return A list of the task IDs for tasks that must complete before this 1212 * task will be eligible to start, or an empty list if this task does 1213 * not have any dependencies. 1214 */ 1215 @NotNull() 1216 public final List<String> getDependencyIDs() 1217 { 1218 return dependencyIDs; 1219 } 1220 1221 1222 1223 /** 1224 * Retrieves the failed dependency action for this task, which indicates the 1225 * behavior that it should exhibit if any of its dependencies encounter a 1226 * failure. 1227 * 1228 * @return The failed dependency action for this task, or {@code null} if it 1229 * is not available. 1230 */ 1231 @Nullable() 1232 public final FailedDependencyAction getFailedDependencyAction() 1233 { 1234 return failedDependencyAction; 1235 } 1236 1237 1238 1239 /** 1240 * Retrieves the log messages for this task. Note that if the task has 1241 * generated a very large number of log messages, then only a portion of the 1242 * most recent messages may be available. 1243 * 1244 * @return The log messages for this task, or an empty list if this task does 1245 * not have any log messages. 1246 */ 1247 @NotNull() 1248 public final List<String> getLogMessages() 1249 { 1250 return logMessages; 1251 } 1252 1253 1254 1255 /** 1256 * Retrieves a list of the e-mail addresses of the individuals that should be 1257 * notified whenever this task starts running. 1258 * 1259 * @return A list of the e-mail addresses of the individuals that should be 1260 * notified whenever this task starts running, or an empty list if 1261 * there are none. 1262 */ 1263 @NotNull() 1264 public final List<String> getNotifyOnStartAddresses() 1265 { 1266 return notifyOnStart; 1267 } 1268 1269 1270 1271 /** 1272 * Retrieves a list of the e-mail addresses of the individuals that should be 1273 * notified whenever this task completes processing, regardless of whether it 1274 * was successful. 1275 * 1276 * @return A list of the e-mail addresses of the individuals that should be 1277 * notified whenever this task completes processing, or an empty list 1278 * if there are none. 1279 */ 1280 @NotNull() 1281 public final List<String> getNotifyOnCompletionAddresses() 1282 { 1283 return notifyOnCompletion; 1284 } 1285 1286 1287 1288 /** 1289 * Retrieves a list of the e-mail addresses of the individuals that should be 1290 * notified if this task completes successfully. 1291 * 1292 * @return A list of the e-mail addresses of the individuals that should be 1293 * notified if this task completes successfully, or an empty list 1294 * if there are none. 1295 */ 1296 @NotNull() 1297 public final List<String> getNotifyOnSuccessAddresses() 1298 { 1299 return notifyOnSuccess; 1300 } 1301 1302 1303 1304 /** 1305 * Retrieves a list of the e-mail addresses of the individuals that should be 1306 * notified if this task stops processing prematurely due to an error or 1307 * other external action (e.g., server shutdown or administrative cancel). 1308 * 1309 * @return A list of the e-mail addresses of the individuals that should be 1310 * notified if this task stops processing prematurely, or an empty 1311 * list if there are none. 1312 */ 1313 @NotNull() 1314 public final List<String> getNotifyOnErrorAddresses() 1315 { 1316 return notifyOnError; 1317 } 1318 1319 1320 1321 /** 1322 * Retrieves the flag that indicates whether the server should generate an 1323 * administrative alert when this task starts running. 1324 * 1325 * @return {@code true} if the server should send an alert when this task 1326 * starts running, {@code false} if the server should not send an 1327 * alert, or {@code null} if it is not available. 1328 */ 1329 @Nullable() 1330 public final Boolean getAlertOnStart() 1331 { 1332 return alertOnStart; 1333 } 1334 1335 1336 1337 /** 1338 * Retrieves the flag that indicates whether the server should generate an 1339 * administrative alert if this task completes successfully. 1340 * 1341 * @return {@code true} if the server should send an alert if this task 1342 * completes successfully, {@code false} if the server should not 1343 * send an alert, or {@code null} if it is not available. 1344 */ 1345 @Nullable() 1346 public final Boolean getAlertOnSuccess() 1347 { 1348 return alertOnSuccess; 1349 } 1350 1351 1352 1353 /** 1354 * Retrieves the flag that indicates whether the server should generate an 1355 * administrative alert if this task fails to complete successfully. 1356 * 1357 * @return {@code true} if the server should send an alert if this task fails 1358 * to complete successfully, {@code false} if the server should not 1359 * send an alert, or {@code null} if it is not available. 1360 */ 1361 @Nullable() 1362 public final Boolean getAlertOnError() 1363 { 1364 return alertOnError; 1365 } 1366 1367 1368 1369 /** 1370 * Creates an entry that may be added to the Directory Server to create a new 1371 * instance of this task. 1372 * 1373 * @return An entry that may be added to the Directory Server to create a new 1374 * instance of this task. 1375 */ 1376 @NotNull() 1377 public final Entry createTaskEntry() 1378 { 1379 final ArrayList<Attribute> attributes = new ArrayList<>(20); 1380 1381 final ArrayList<String> ocValues = new ArrayList<>(5); 1382 ocValues.add("top"); 1383 ocValues.add(OC_TASK); 1384 ocValues.addAll(getAdditionalObjectClasses()); 1385 attributes.add(new Attribute("objectClass", ocValues)); 1386 1387 attributes.add(new Attribute(ATTR_TASK_ID, taskID)); 1388 1389 attributes.add(new Attribute(ATTR_TASK_CLASS, taskClassName)); 1390 1391 if (scheduledStartTime != null) 1392 { 1393 attributes.add(new Attribute(ATTR_SCHEDULED_START_TIME, 1394 StaticUtils.encodeGeneralizedTime(scheduledStartTime))); 1395 } 1396 1397 if (! dependencyIDs.isEmpty()) 1398 { 1399 attributes.add(new Attribute(ATTR_DEPENDENCY_ID, dependencyIDs)); 1400 } 1401 1402 if (failedDependencyAction != null) 1403 { 1404 attributes.add(new Attribute(ATTR_FAILED_DEPENDENCY_ACTION, 1405 failedDependencyAction.getName())); 1406 } 1407 1408 if (! notifyOnStart.isEmpty()) 1409 { 1410 attributes.add(new Attribute(ATTR_NOTIFY_ON_START, 1411 notifyOnStart)); 1412 } 1413 1414 if (! notifyOnCompletion.isEmpty()) 1415 { 1416 attributes.add(new Attribute(ATTR_NOTIFY_ON_COMPLETION, 1417 notifyOnCompletion)); 1418 } 1419 1420 if (! notifyOnSuccess.isEmpty()) 1421 { 1422 attributes.add(new Attribute(ATTR_NOTIFY_ON_SUCCESS, notifyOnSuccess)); 1423 } 1424 1425 if (! notifyOnError.isEmpty()) 1426 { 1427 attributes.add(new Attribute(ATTR_NOTIFY_ON_ERROR, notifyOnError)); 1428 } 1429 1430 if (alertOnStart != null) 1431 { 1432 attributes.add(new Attribute(ATTR_ALERT_ON_START, 1433 String.valueOf(alertOnStart))); 1434 } 1435 1436 if (alertOnSuccess != null) 1437 { 1438 attributes.add(new Attribute(ATTR_ALERT_ON_SUCCESS, 1439 String.valueOf(alertOnSuccess))); 1440 } 1441 1442 if (alertOnError != null) 1443 { 1444 attributes.add(new Attribute(ATTR_ALERT_ON_ERROR, 1445 String.valueOf(alertOnError))); 1446 } 1447 1448 attributes.addAll(getAdditionalAttributes()); 1449 1450 return new Entry(taskEntryDN, attributes); 1451 } 1452 1453 1454 1455 /** 1456 * Parses the value of the specified attribute as a {@code boolean} value, or 1457 * throws an exception if the value cannot be decoded as a boolean. 1458 * 1459 * @param taskEntry The entry containing the attribute to be parsed. 1460 * @param attributeName The name of the attribute from which the value was 1461 * taken. 1462 * @param defaultValue The default value to use if the provided value 1463 * string is {@code null}. 1464 * 1465 * @return {@code true} if the value string represents a boolean value of 1466 * {@code true}, {@code false} if the value string represents a 1467 * boolean value of {@code false}, or the default value if the value 1468 * string is {@code null}. 1469 * 1470 * @throws TaskException If the provided value string cannot be parsed as a 1471 * {@code boolean} value. 1472 */ 1473 protected static boolean parseBooleanValue(@NotNull final Entry taskEntry, 1474 @NotNull final String attributeName, 1475 final boolean defaultValue) 1476 throws TaskException 1477 { 1478 final String valueString = taskEntry.getAttributeValue(attributeName); 1479 if (valueString == null) 1480 { 1481 return defaultValue; 1482 } 1483 else if (valueString.equalsIgnoreCase("true")) 1484 { 1485 return true; 1486 } 1487 else if (valueString.equalsIgnoreCase("false")) 1488 { 1489 return false; 1490 } 1491 else 1492 { 1493 throw new TaskException(ERR_TASK_CANNOT_PARSE_BOOLEAN.get( 1494 taskEntry.getDN(), valueString, 1495 attributeName)); 1496 } 1497 } 1498 1499 1500 1501 /** 1502 * Parses the values of the specified attribute as a list of strings. 1503 * 1504 * @param taskEntry The entry containing the attribute to be parsed. 1505 * @param attributeName The name of the attribute from which the value was 1506 * taken. 1507 * 1508 * @return A list of strings containing the values of the specified 1509 * attribute, or an empty list if the specified attribute does not 1510 * exist in the target entry. The returned list will be 1511 * unmodifiable. 1512 */ 1513 @NotNull() 1514 protected static List<String> parseStringList(@NotNull final Entry taskEntry, 1515 @NotNull final String attributeName) 1516 { 1517 final String[] valueStrings = taskEntry.getAttributeValues(attributeName); 1518 if (valueStrings == null) 1519 { 1520 return Collections.emptyList(); 1521 } 1522 else 1523 { 1524 return Collections.unmodifiableList(Arrays.asList(valueStrings)); 1525 } 1526 } 1527 1528 1529 1530 /** 1531 * Parses the provided set of values for the associated task property as a 1532 * {@code Boolean}. 1533 * 1534 * @param p The task property with which the values are 1535 * associated. 1536 * @param values The provided values for the task property. 1537 * @param defaultValue The default value to use if the provided object array 1538 * is empty. 1539 * 1540 * @return The parsed {@code Boolean} value. 1541 * 1542 * @throws TaskException If there is a problem with the provided values. 1543 */ 1544 @Nullable() 1545 protected static Boolean parseBoolean(@NotNull final TaskProperty p, 1546 @NotNull final List<Object> values, 1547 @Nullable final Boolean defaultValue) 1548 throws TaskException 1549 { 1550 // Check to see if any values were provided. If not, then it may or may not 1551 // be a problem. 1552 if (values.isEmpty()) 1553 { 1554 if (p.isRequired()) 1555 { 1556 throw new TaskException(ERR_TASK_REQUIRED_PROPERTY_WITHOUT_VALUES.get( 1557 p.getDisplayName())); 1558 } 1559 else 1560 { 1561 return defaultValue; 1562 } 1563 } 1564 1565 // If there were multiple values, then that's always an error. 1566 if (values.size() > 1) 1567 { 1568 throw new TaskException(ERR_TASK_PROPERTY_NOT_MULTIVALUED.get( 1569 p.getDisplayName())); 1570 } 1571 1572 // Make sure that the value can be interpreted as a Boolean. 1573 final Boolean booleanValue; 1574 final Object o = values.get(0); 1575 if (o instanceof Boolean) 1576 { 1577 booleanValue = (Boolean) o; 1578 } 1579 else if (o instanceof String) 1580 { 1581 final String valueStr = (String) o; 1582 if (valueStr.equalsIgnoreCase("true")) 1583 { 1584 booleanValue = Boolean.TRUE; 1585 } 1586 else if (valueStr.equalsIgnoreCase("false")) 1587 { 1588 booleanValue = Boolean.FALSE; 1589 } 1590 else 1591 { 1592 throw new TaskException(ERR_TASK_PROPERTY_VALUE_NOT_BOOLEAN.get( 1593 p.getDisplayName())); 1594 } 1595 } 1596 else 1597 { 1598 throw new TaskException(ERR_TASK_PROPERTY_VALUE_NOT_BOOLEAN.get( 1599 p.getDisplayName())); 1600 } 1601 1602 return booleanValue; 1603 } 1604 1605 1606 1607 /** 1608 * Parses the provided set of values for the associated task property as a 1609 * {@code Date}. 1610 * 1611 * @param p The task property with which the values are 1612 * associated. 1613 * @param values The provided values for the task property. 1614 * @param defaultValue The default value to use if the provided object array 1615 * is empty. 1616 * 1617 * @return The parsed {@code Date} value. 1618 * 1619 * @throws TaskException If there is a problem with the provided values. 1620 */ 1621 @Nullable() 1622 protected static Date parseDate(@NotNull final TaskProperty p, 1623 @NotNull final List<Object> values, 1624 @Nullable final Date defaultValue) 1625 throws TaskException 1626 { 1627 // Check to see if any values were provided. If not, then it may or may not 1628 // be a problem. 1629 if (values.isEmpty()) 1630 { 1631 if (p.isRequired()) 1632 { 1633 throw new TaskException(ERR_TASK_REQUIRED_PROPERTY_WITHOUT_VALUES.get( 1634 p.getDisplayName())); 1635 } 1636 else 1637 { 1638 return defaultValue; 1639 } 1640 } 1641 1642 // If there were multiple values, then that's always an error. 1643 if (values.size() > 1) 1644 { 1645 throw new TaskException(ERR_TASK_PROPERTY_NOT_MULTIVALUED.get( 1646 p.getDisplayName())); 1647 } 1648 1649 // Make sure that the value can be interpreted as a Date. 1650 final Date dateValue; 1651 final Object o = values.get(0); 1652 if (o instanceof Date) 1653 { 1654 dateValue = (Date) o; 1655 } 1656 else if (o instanceof String) 1657 { 1658 try 1659 { 1660 dateValue = StaticUtils.decodeGeneralizedTime((String) o); 1661 } 1662 catch (final ParseException pe) 1663 { 1664 throw new TaskException(ERR_TASK_PROPERTY_VALUE_NOT_DATE.get( 1665 p.getDisplayName()), pe); 1666 } 1667 } 1668 else 1669 { 1670 throw new TaskException(ERR_TASK_PROPERTY_VALUE_NOT_DATE.get( 1671 p.getDisplayName())); 1672 } 1673 1674 // If the task property has a set of allowed values, then make sure that the 1675 // provided value is acceptable. 1676 final Object[] allowedValues = p.getAllowedValues(); 1677 if (allowedValues != null) 1678 { 1679 boolean found = false; 1680 for (final Object allowedValue : allowedValues) 1681 { 1682 if (dateValue.equals(allowedValue)) 1683 { 1684 found = true; 1685 break; 1686 } 1687 } 1688 1689 if (! found) 1690 { 1691 throw new TaskException(ERR_TASK_PROPERTY_VALUE_NOT_ALLOWED.get( 1692 p.getDisplayName(), dateValue.toString())); 1693 } 1694 } 1695 1696 return dateValue; 1697 } 1698 1699 1700 1701 /** 1702 * Parses the provided set of values for the associated task property as a 1703 * {@code Long}. 1704 * 1705 * @param p The task property with which the values are 1706 * associated. 1707 * @param values The provided values for the task property. 1708 * @param defaultValue The default value to use if the provided object array 1709 * is empty. 1710 * 1711 * @return The parsed {@code Long} value. 1712 * 1713 * @throws TaskException If there is a problem with the provided values. 1714 */ 1715 @Nullable() 1716 protected static Long parseLong(@NotNull final TaskProperty p, 1717 @NotNull final List<Object> values, 1718 @Nullable final Long defaultValue) 1719 throws TaskException 1720 { 1721 // Check to see if any values were provided. If not, then it may or may not 1722 // be a problem. 1723 if (values.isEmpty()) 1724 { 1725 if (p.isRequired()) 1726 { 1727 throw new TaskException(ERR_TASK_REQUIRED_PROPERTY_WITHOUT_VALUES.get( 1728 p.getDisplayName())); 1729 } 1730 else 1731 { 1732 return defaultValue; 1733 } 1734 } 1735 1736 // If there were multiple values, then that's always an error. 1737 if (values.size() > 1) 1738 { 1739 throw new TaskException(ERR_TASK_PROPERTY_NOT_MULTIVALUED.get( 1740 p.getDisplayName())); 1741 } 1742 1743 // Make sure that the value can be interpreted as a Long. 1744 final Long longValue; 1745 final Object o = values.get(0); 1746 if (o instanceof Long) 1747 { 1748 longValue = (Long) o; 1749 } 1750 else if (o instanceof Number) 1751 { 1752 longValue = ((Number) o).longValue(); 1753 } 1754 else if (o instanceof String) 1755 { 1756 try 1757 { 1758 longValue = Long.parseLong((String) o); 1759 } 1760 catch (final Exception e) 1761 { 1762 throw new TaskException(ERR_TASK_PROPERTY_VALUE_NOT_LONG.get( 1763 p.getDisplayName()), e); 1764 } 1765 } 1766 else 1767 { 1768 throw new TaskException(ERR_TASK_PROPERTY_VALUE_NOT_LONG.get( 1769 p.getDisplayName())); 1770 } 1771 1772 // If the task property has a set of allowed values, then make sure that the 1773 // provided value is acceptable. 1774 final Object[] allowedValues = p.getAllowedValues(); 1775 if (allowedValues != null) 1776 { 1777 boolean found = false; 1778 for (final Object allowedValue : allowedValues) 1779 { 1780 if (longValue.equals(allowedValue)) 1781 { 1782 found = true; 1783 break; 1784 } 1785 } 1786 1787 if (! found) 1788 { 1789 throw new TaskException(ERR_TASK_PROPERTY_VALUE_NOT_ALLOWED.get( 1790 p.getDisplayName(), longValue.toString())); 1791 } 1792 } 1793 1794 return longValue; 1795 } 1796 1797 1798 1799 /** 1800 * Parses the provided set of values for the associated task property as a 1801 * {@code String}. 1802 * 1803 * @param p The task property with which the values are 1804 * associated. 1805 * @param values The provided values for the task property. 1806 * @param defaultValue The default value to use if the provided object array 1807 * is empty. 1808 * 1809 * @return The parsed {@code String} value. 1810 * 1811 * @throws TaskException If there is a problem with the provided values. 1812 */ 1813 @Nullable() 1814 protected static String parseString(@NotNull final TaskProperty p, 1815 @NotNull final List<Object> values, 1816 @Nullable final String defaultValue) 1817 throws TaskException 1818 { 1819 // Check to see if any values were provided. If not, then it may or may not 1820 // be a problem. 1821 if (values.isEmpty()) 1822 { 1823 if (p.isRequired()) 1824 { 1825 throw new TaskException(ERR_TASK_REQUIRED_PROPERTY_WITHOUT_VALUES.get( 1826 p.getDisplayName())); 1827 } 1828 else 1829 { 1830 return defaultValue; 1831 } 1832 } 1833 1834 // If there were multiple values, then that's always an error. 1835 if (values.size() > 1) 1836 { 1837 throw new TaskException(ERR_TASK_PROPERTY_NOT_MULTIVALUED.get( 1838 p.getDisplayName())); 1839 } 1840 1841 // Make sure that the value is a String. 1842 final String valueStr; 1843 final Object o = values.get(0); 1844 if (o instanceof String) 1845 { 1846 valueStr = (String) o; 1847 } 1848 else if (values.get(0) instanceof CharSequence) 1849 { 1850 valueStr = o.toString(); 1851 } 1852 else 1853 { 1854 throw new TaskException(ERR_TASK_PROPERTY_VALUE_NOT_STRING.get( 1855 p.getDisplayName())); 1856 } 1857 1858 // If the task property has a set of allowed values, then make sure that the 1859 // provided value is acceptable. 1860 final Object[] allowedValues = p.getAllowedValues(); 1861 if (allowedValues != null) 1862 { 1863 boolean found = false; 1864 for (final Object allowedValue : allowedValues) 1865 { 1866 final String s = (String) allowedValue; 1867 if (valueStr.equalsIgnoreCase(s)) 1868 { 1869 found = true; 1870 break; 1871 } 1872 } 1873 1874 if (! found) 1875 { 1876 throw new TaskException(ERR_TASK_PROPERTY_VALUE_NOT_ALLOWED.get( 1877 p.getDisplayName(), valueStr)); 1878 } 1879 } 1880 1881 return valueStr; 1882 } 1883 1884 1885 1886 /** 1887 * Parses the provided set of values for the associated task property as a 1888 * {@code String} array. 1889 * 1890 * @param p The task property with which the values are 1891 * associated. 1892 * @param values The provided values for the task property. 1893 * @param defaultValues The set of default values to use if the provided 1894 * object array is empty. 1895 * 1896 * @return The parsed {@code String} values. 1897 * 1898 * @throws TaskException If there is a problem with the provided values. 1899 */ 1900 @Nullable() 1901 protected static String[] parseStrings(@NotNull final TaskProperty p, 1902 @NotNull final List<Object> values, 1903 @Nullable final String[] defaultValues) 1904 throws TaskException 1905 { 1906 // Check to see if any values were provided. If not, then it may or may not 1907 // be a problem. 1908 if (values.isEmpty()) 1909 { 1910 if (p.isRequired()) 1911 { 1912 throw new TaskException(ERR_TASK_REQUIRED_PROPERTY_WITHOUT_VALUES.get( 1913 p.getDisplayName())); 1914 } 1915 else 1916 { 1917 return defaultValues; 1918 } 1919 } 1920 1921 1922 // Iterate through each of the values and perform appropriate validation for 1923 // them. 1924 final String[] stringValues = new String[values.size()]; 1925 for (int i=0; i < values.size(); i++) 1926 { 1927 final Object o = values.get(i); 1928 1929 // Make sure that the value is a String. 1930 final String valueStr; 1931 if (o instanceof String) 1932 { 1933 valueStr = (String) o; 1934 } 1935 else if (o instanceof CharSequence) 1936 { 1937 valueStr = o.toString(); 1938 } 1939 else 1940 { 1941 throw new TaskException(ERR_TASK_PROPERTY_VALUE_NOT_STRING.get( 1942 p.getDisplayName())); 1943 } 1944 1945 // If the task property has a set of allowed values, then make sure that 1946 // the provided value is acceptable. 1947 final Object[] allowedValues = p.getAllowedValues(); 1948 if (allowedValues != null) 1949 { 1950 boolean found = false; 1951 for (final Object allowedValue : allowedValues) 1952 { 1953 final String s = (String) allowedValue; 1954 if (valueStr.equalsIgnoreCase(s)) 1955 { 1956 found = true; 1957 break; 1958 } 1959 } 1960 1961 if (! found) 1962 { 1963 throw new TaskException(ERR_TASK_PROPERTY_VALUE_NOT_ALLOWED.get( 1964 p.getDisplayName(), valueStr)); 1965 } 1966 } 1967 1968 stringValues[i] = valueStr; 1969 } 1970 1971 return stringValues; 1972 } 1973 1974 1975 1976 /** 1977 * Retrieves a list of the additional object classes (other than the base 1978 * "top" and "ds-task" classes) that should be included when creating new task 1979 * entries of this type. 1980 * 1981 * @return A list of the additional object classes that should be included in 1982 * new task entries of this type, or an empty list if there do not 1983 * need to be any additional classes. 1984 */ 1985 @NotNull() 1986 protected List<String> getAdditionalObjectClasses() 1987 { 1988 return Collections.emptyList(); 1989 } 1990 1991 1992 1993 /** 1994 * Retrieves a list of the additional attributes (other than attributes common 1995 * to all task types) that should be included when creating new task entries 1996 * of this type. 1997 * 1998 * @return A list of the additional attributes that should be included in new 1999 * task entries of this type, or an empty list if there do not need 2000 * to be any additional attributes. 2001 */ 2002 @NotNull() 2003 protected List<Attribute> getAdditionalAttributes() 2004 { 2005 return Collections.emptyList(); 2006 } 2007 2008 2009 2010 /** 2011 * Decodes the provided entry as a scheduled task. An attempt will be made to 2012 * decode the entry as an appropriate subclass if possible, but it will fall 2013 * back to a generic task if it is not possible to decode as a more specific 2014 * task type. 2015 * 2016 * @param entry The entry to be decoded. 2017 * 2018 * @return The decoded task. 2019 * 2020 * @throws TaskException If the provided entry cannot be parsed as a 2021 * scheduled task. 2022 */ 2023 @NotNull() 2024 public static Task decodeTask(@NotNull final Entry entry) 2025 throws TaskException 2026 { 2027 final String taskClass = entry.getAttributeValue(ATTR_TASK_CLASS); 2028 if (taskClass == null) 2029 { 2030 throw new TaskException(ERR_TASK_NO_CLASS.get(entry.getDN())); 2031 } 2032 2033 try 2034 { 2035 if (taskClass.equals(AddSchemaFileTask.ADD_SCHEMA_FILE_TASK_CLASS)) 2036 { 2037 return new AddSchemaFileTask(entry); 2038 } 2039 else if (taskClass.equals(AlertTask.ALERT_TASK_CLASS)) 2040 { 2041 return new AlertTask(entry); 2042 } 2043 else if (taskClass.equals(AuditDataSecurityTask. 2044 AUDIT_DATA_SECURITY_TASK_CLASS)) 2045 { 2046 return new AuditDataSecurityTask(entry); 2047 } 2048 else if (taskClass.equals(BackupTask.BACKUP_TASK_CLASS)) 2049 { 2050 return new BackupTask(entry); 2051 } 2052 else if (taskClass.equals( 2053 CollectSupportDataTask.COLLECT_SUPPORT_DATA_TASK_CLASS)) 2054 { 2055 return new CollectSupportDataTask(entry); 2056 } 2057 else if (taskClass.equals(DelayTask.DELAY_TASK_CLASS)) 2058 { 2059 return new DelayTask(entry); 2060 } 2061 else if (taskClass.equals( 2062 DisconnectClientTask.DISCONNECT_CLIENT_TASK_CLASS)) 2063 { 2064 return new DisconnectClientTask(entry); 2065 } 2066 else if (taskClass.equals(DumpDBDetailsTask.DUMP_DB_DETAILS_TASK_CLASS)) 2067 { 2068 return new DumpDBDetailsTask(entry); 2069 } 2070 else if (taskClass.equals( 2071 EnterLockdownModeTask.ENTER_LOCKDOWN_MODE_TASK_CLASS)) 2072 { 2073 return new EnterLockdownModeTask(entry); 2074 } 2075 else if (taskClass.equals(ExecTask.EXEC_TASK_CLASS)) 2076 { 2077 return new ExecTask(entry); 2078 } 2079 else if (taskClass.equals(ExportTask.EXPORT_TASK_CLASS)) 2080 { 2081 return new ExportTask(entry); 2082 } 2083 else if (taskClass.equals(FileRetentionTask.FILE_RETENTION_TASK_CLASS)) 2084 { 2085 return new FileRetentionTask(entry); 2086 } 2087 else if (taskClass.equals( 2088 GenerateServerProfileTask.GENERATE_SERVER_PROFILE_TASK_CLASS)) 2089 { 2090 return new GenerateServerProfileTask(entry); 2091 } 2092 else if (taskClass.equals(GroovyScriptedTask.GROOVY_SCRIPTED_TASK_CLASS)) 2093 { 2094 return new GroovyScriptedTask(entry); 2095 } 2096 else if (taskClass.equals(ImportTask.IMPORT_TASK_CLASS)) 2097 { 2098 return new ImportTask(entry); 2099 } 2100 else if (taskClass.equals( 2101 LeaveLockdownModeTask.LEAVE_LOCKDOWN_MODE_TASK_CLASS)) 2102 { 2103 return new LeaveLockdownModeTask(entry); 2104 } 2105 else if (taskClass.equals( 2106 PopulateComposedAttributeValuesTask. 2107 POPULATE_COMPOSED_ATTRIBUTE_VALUES_TASK_CLASS)) 2108 { 2109 return new PopulateComposedAttributeValuesTask(entry); 2110 } 2111 else if (taskClass.equals(RebuildTask.REBUILD_TASK_CLASS)) 2112 { 2113 return new RebuildTask(entry); 2114 } 2115 else if (taskClass.equals( 2116 ReEncodeEntriesTask.RE_ENCODE_ENTRIES_TASK_CLASS)) 2117 { 2118 return new ReEncodeEntriesTask(entry); 2119 } 2120 else if (taskClass.equals(RefreshEncryptionSettingsTask. 2121 REFRESH_ENCRYPTION_SETTINGS_TASK_CLASS)) 2122 { 2123 return new RefreshEncryptionSettingsTask(entry); 2124 } 2125 else if (taskClass.equals( 2126 ReloadGlobalIndexTask.RELOAD_GLOBAL_INDEX_TASK_CLASS)) 2127 { 2128 return new ReloadGlobalIndexTask(entry); 2129 } 2130 else if (taskClass.equals( 2131 ReloadHTTPConnectionHandlerCertificatesTask. 2132 RELOAD_HTTP_CONNECTION_HANDLER_CERTIFICATES_TASK_CLASS)) 2133 { 2134 return new ReloadHTTPConnectionHandlerCertificatesTask(entry); 2135 } 2136 else if (taskClass.equals(RestoreTask.RESTORE_TASK_CLASS)) 2137 { 2138 return new RestoreTask(entry); 2139 } 2140 else if (taskClass.equals(RotateLogTask.ROTATE_LOG_TASK_CLASS)) 2141 { 2142 return new RotateLogTask(entry); 2143 } 2144 else if (taskClass.equals(SearchTask.SEARCH_TASK_CLASS)) 2145 { 2146 return new SearchTask(entry); 2147 } 2148 else if (taskClass.equals(ShutdownTask.SHUTDOWN_TASK_CLASS)) 2149 { 2150 return new ShutdownTask(entry); 2151 } 2152 else if (taskClass.equals(SynchronizeEncryptionSettingsTask. 2153 SYNCHRONIZE_ENCRYPTION_SETTINGS_TASK_CLASS)) 2154 { 2155 return new SynchronizeEncryptionSettingsTask(entry); 2156 } 2157 else if (taskClass.equals(ThirdPartyTask.THIRD_PARTY_TASK_CLASS)) 2158 { 2159 return new ThirdPartyTask(entry); 2160 } 2161 } 2162 catch (final TaskException te) 2163 { 2164 Debug.debugException(te); 2165 } 2166 2167 return new Task(entry); 2168 } 2169 2170 2171 2172 /** 2173 * Retrieves a list of task properties that may be provided when scheduling 2174 * any type of task. This includes: 2175 * <UL> 2176 * <LI>The task ID</LI> 2177 * <LI>The scheduled start time</LI> 2178 * <LI>The task IDs of any tasks on which this task is dependent</LI> 2179 * <LI>The action to take for this task if any of its dependencies fail</LI> 2180 * <LI>The addresses of users to notify when this task starts</LI> 2181 * <LI>The addresses of users to notify when this task completes</LI> 2182 * <LI>The addresses of users to notify if this task succeeds</LI> 2183 * <LI>The addresses of users to notify if this task fails</LI> 2184 * <LI>A flag indicating whether to generate an alert when the task 2185 * starts</LI> 2186 * <LI>A flag indicating whether to generate an alert when the task 2187 * succeeds</LI> 2188 * <LI>A flag indicating whether to generate an alert when the task 2189 * fails</LI> 2190 * </UL> 2191 * 2192 * @return A list of task properties that may be provided when scheduling any 2193 * type of task. 2194 */ 2195 @NotNull() 2196 public static List<TaskProperty> getCommonTaskProperties() 2197 { 2198 final List<TaskProperty> taskList = Arrays.asList( 2199 PROPERTY_TASK_ID, 2200 PROPERTY_SCHEDULED_START_TIME, 2201 PROPERTY_DEPENDENCY_ID, 2202 PROPERTY_FAILED_DEPENDENCY_ACTION, 2203 PROPERTY_NOTIFY_ON_START, 2204 PROPERTY_NOTIFY_ON_COMPLETION, 2205 PROPERTY_NOTIFY_ON_SUCCESS, 2206 PROPERTY_NOTIFY_ON_ERROR, 2207 PROPERTY_ALERT_ON_START, 2208 PROPERTY_ALERT_ON_SUCCESS, 2209 PROPERTY_ALERT_ON_ERROR); 2210 2211 return Collections.unmodifiableList(taskList); 2212 } 2213 2214 2215 2216 /** 2217 * Retrieves a list of task-specific properties that may be provided when 2218 * scheduling a task of this type. This method should be overridden by 2219 * subclasses in order to provide an appropriate set of properties. 2220 * 2221 * @return A list of task-specific properties that may be provided when 2222 * scheduling a task of this type. 2223 */ 2224 @NotNull() 2225 public List<TaskProperty> getTaskSpecificProperties() 2226 { 2227 return Collections.emptyList(); 2228 } 2229 2230 2231 2232 /** 2233 * Retrieves the values of the task properties for this task. The data type 2234 * of the values will vary based on the data type of the corresponding task 2235 * property and may be one of the following types: {@code Boolean}, 2236 * {@code Date}, {@code Long}, or {@code String}. Task properties which do 2237 * not have any values will be included in the map with an empty value list. 2238 * <BR><BR> 2239 * Note that subclasses which have additional task properties should override 2240 * this method and return a map which contains both the property values from 2241 * this class (obtained from {@code super.getTaskPropertyValues()} and the 2242 * values of their own task-specific properties. 2243 * 2244 * @return A map of the task property values for this task. 2245 */ 2246 @NotNull() 2247 public Map<TaskProperty,List<Object>> getTaskPropertyValues() 2248 { 2249 final LinkedHashMap<TaskProperty,List<Object>> props = 2250 new LinkedHashMap<>(StaticUtils.computeMapCapacity(20)); 2251 2252 props.put(PROPERTY_TASK_ID, 2253 Collections.<Object>singletonList(taskID)); 2254 2255 if (scheduledStartTime == null) 2256 { 2257 props.put(PROPERTY_SCHEDULED_START_TIME, Collections.emptyList()); 2258 } 2259 else 2260 { 2261 props.put(PROPERTY_SCHEDULED_START_TIME, 2262 Collections.<Object>singletonList(scheduledStartTime)); 2263 } 2264 2265 props.put(PROPERTY_DEPENDENCY_ID, 2266 Collections.<Object>unmodifiableList(dependencyIDs)); 2267 2268 if (failedDependencyAction == null) 2269 { 2270 props.put(PROPERTY_FAILED_DEPENDENCY_ACTION, Collections.emptyList()); 2271 } 2272 else 2273 { 2274 props.put(PROPERTY_FAILED_DEPENDENCY_ACTION, 2275 Collections.<Object>singletonList(failedDependencyAction.getName())); 2276 } 2277 2278 props.put(PROPERTY_NOTIFY_ON_START, 2279 Collections.<Object>unmodifiableList(notifyOnStart)); 2280 2281 props.put(PROPERTY_NOTIFY_ON_COMPLETION, 2282 Collections.<Object>unmodifiableList(notifyOnCompletion)); 2283 2284 props.put(PROPERTY_NOTIFY_ON_SUCCESS, 2285 Collections.<Object>unmodifiableList(notifyOnSuccess)); 2286 2287 props.put(PROPERTY_NOTIFY_ON_ERROR, 2288 Collections.<Object>unmodifiableList(notifyOnError)); 2289 2290 if (alertOnStart != null) 2291 { 2292 props.put(PROPERTY_ALERT_ON_START, 2293 Collections.<Object>singletonList(alertOnStart)); 2294 } 2295 2296 if (alertOnSuccess != null) 2297 { 2298 props.put(PROPERTY_ALERT_ON_SUCCESS, 2299 Collections.<Object>singletonList(alertOnSuccess)); 2300 } 2301 2302 if (alertOnError!= null) 2303 { 2304 props.put(PROPERTY_ALERT_ON_ERROR, 2305 Collections.<Object>singletonList(alertOnError)); 2306 } 2307 2308 return Collections.unmodifiableMap(props); 2309 } 2310 2311 2312 2313 /** 2314 * Retrieves a string representation of this task. 2315 * 2316 * @return A string representation of this task. 2317 */ 2318 @Override() 2319 @NotNull() 2320 public final String toString() 2321 { 2322 final StringBuilder buffer = new StringBuilder(); 2323 toString(buffer); 2324 return buffer.toString(); 2325 } 2326 2327 2328 2329 /** 2330 * Appends a string representation of this task to the provided buffer. 2331 * 2332 * @param buffer The buffer to which the string representation should be 2333 * provided. 2334 */ 2335 public final void toString(@NotNull final StringBuilder buffer) 2336 { 2337 buffer.append("Task(name='"); 2338 buffer.append(getTaskName()); 2339 buffer.append("', className='"); 2340 buffer.append(taskClassName); 2341 buffer.append(", properties={"); 2342 2343 boolean added = false; 2344 for (final Map.Entry<TaskProperty,List<Object>> e : 2345 getTaskPropertyValues().entrySet()) 2346 { 2347 if (added) 2348 { 2349 buffer.append(", "); 2350 } 2351 else 2352 { 2353 added = true; 2354 } 2355 2356 buffer.append(e.getKey().getAttributeName()); 2357 buffer.append("={"); 2358 2359 final Iterator<Object> iterator = e.getValue().iterator(); 2360 while (iterator.hasNext()) 2361 { 2362 buffer.append('\''); 2363 buffer.append(String.valueOf(iterator.next())); 2364 buffer.append('\''); 2365 2366 if (iterator.hasNext()) 2367 { 2368 buffer.append(','); 2369 } 2370 } 2371 2372 buffer.append('}'); 2373 } 2374 2375 buffer.append("})"); 2376 } 2377}