001/* 002 * Copyright 2008-2021 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2008-2021 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-2021 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; 050 051import com.unboundid.ldap.sdk.Attribute; 052import com.unboundid.ldap.sdk.Entry; 053import com.unboundid.util.CryptoHelper; 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 = CryptoHelper.getRandomUUID().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 = CryptoHelper.getRandomUUID().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 RemoveAttributeTypeTask(), 1017 new RemoveObjectClassTask(), 1018 new RestoreTask(), 1019 new RotateLogTask(), 1020 new SearchTask(), 1021 new ShutdownTask(), 1022 new SynchronizeEncryptionSettingsTask(), 1023 new ThirdPartyTask()); 1024 1025 return Collections.unmodifiableList(taskList); 1026 } 1027 1028 1029 1030 /** 1031 * Retrieves a human-readable name for this task. 1032 * 1033 * @return A human-readable name for this task. 1034 */ 1035 @NotNull() 1036 public String getTaskName() 1037 { 1038 return INFO_TASK_NAME_GENERIC.get(); 1039 } 1040 1041 1042 1043 /** 1044 * Retrieves a human-readable description for this task. 1045 * 1046 * @return A human-readable description for this task. 1047 */ 1048 @NotNull() 1049 public String getTaskDescription() 1050 { 1051 return INFO_TASK_DESCRIPTION_GENERIC.get(); 1052 } 1053 1054 1055 1056 /** 1057 * Retrieves the entry from which this task was decoded, if available. Note 1058 * that although the entry is not immutable, changes made to it will not be 1059 * reflected in this task. 1060 * 1061 * @return The entry from which this task was decoded, or {@code null} if 1062 * this task was not created from an existing entry. 1063 */ 1064 @Nullable() 1065 protected final Entry getTaskEntry() 1066 { 1067 return taskEntry; 1068 } 1069 1070 1071 1072 /** 1073 * Retrieves the DN of the entry in which this scheduled task is defined. 1074 * 1075 * @return The DN of the entry in which this scheduled task is defined. 1076 */ 1077 @NotNull() 1078 public final String getTaskEntryDN() 1079 { 1080 return taskEntryDN; 1081 } 1082 1083 1084 1085 /** 1086 * Retrieves the task ID for this task. 1087 * 1088 * @return The task ID for this task. 1089 */ 1090 @NotNull() 1091 public final String getTaskID() 1092 { 1093 return taskID; 1094 } 1095 1096 1097 1098 /** 1099 * Retrieves the fully-qualified name of the Java class that provides the 1100 * logic for this class. 1101 * 1102 * @return The fully-qualified name of the Java class that provides the logic 1103 * for this task. 1104 */ 1105 @NotNull() 1106 public final String getTaskClassName() 1107 { 1108 return taskClassName; 1109 } 1110 1111 1112 1113 /** 1114 * Retrieves the current state for this task. 1115 * 1116 * @return The current state for this task. 1117 */ 1118 @NotNull() 1119 public final TaskState getState() 1120 { 1121 return taskState; 1122 } 1123 1124 1125 1126 /** 1127 * Indicates whether this task is currently pending execution. 1128 * 1129 * @return {@code true} if this task is currently pending execution, or 1130 * {@code false} if not. 1131 */ 1132 public final boolean isPending() 1133 { 1134 return taskState.isPending(); 1135 } 1136 1137 1138 1139 /** 1140 * Indicates whether this task is currently running. 1141 * 1142 * @return {@code true} if this task is currently running, or {@code false} 1143 * if not. 1144 */ 1145 public final boolean isRunning() 1146 { 1147 return taskState.isRunning(); 1148 } 1149 1150 1151 1152 /** 1153 * Indicates whether this task has completed execution. 1154 * 1155 * @return {@code true} if this task has completed execution, or 1156 * {@code false} if not. 1157 */ 1158 public final boolean isCompleted() 1159 { 1160 return taskState.isCompleted(); 1161 } 1162 1163 1164 1165 /** 1166 * Retrieves the time that this task is/was scheduled to start running. 1167 * 1168 * @return The time that this task is/was scheduled to start running, or 1169 * {@code null} if that is not available and therefore the task 1170 * should start running as soon as all dependencies have been met. 1171 */ 1172 @Nullable() 1173 public final Date getScheduledStartTime() 1174 { 1175 return scheduledStartTime; 1176 } 1177 1178 1179 1180 /** 1181 * Retrieves the time that this task actually started running. 1182 * 1183 * @return The time that this task actually started running, or {@code null} 1184 * if that is not available (e.g., because the task has not yet 1185 * started). 1186 */ 1187 @Nullable() 1188 public final Date getActualStartTime() 1189 { 1190 return actualStartTime; 1191 } 1192 1193 1194 1195 /** 1196 * Retrieves the time that this task completed. 1197 * 1198 * @return The time that this task completed, or {@code null} if it has not 1199 * yet completed. 1200 */ 1201 @Nullable() 1202 public final Date getCompletionTime() 1203 { 1204 return completionTime; 1205 } 1206 1207 1208 1209 /** 1210 * Retrieves a list of the task IDs for tasks that must complete before this 1211 * task will be eligible to start. 1212 * 1213 * @return A list of the task IDs for tasks that must complete before this 1214 * task will be eligible to start, or an empty list if this task does 1215 * not have any dependencies. 1216 */ 1217 @NotNull() 1218 public final List<String> getDependencyIDs() 1219 { 1220 return dependencyIDs; 1221 } 1222 1223 1224 1225 /** 1226 * Retrieves the failed dependency action for this task, which indicates the 1227 * behavior that it should exhibit if any of its dependencies encounter a 1228 * failure. 1229 * 1230 * @return The failed dependency action for this task, or {@code null} if it 1231 * is not available. 1232 */ 1233 @Nullable() 1234 public final FailedDependencyAction getFailedDependencyAction() 1235 { 1236 return failedDependencyAction; 1237 } 1238 1239 1240 1241 /** 1242 * Retrieves the log messages for this task. Note that if the task has 1243 * generated a very large number of log messages, then only a portion of the 1244 * most recent messages may be available. 1245 * 1246 * @return The log messages for this task, or an empty list if this task does 1247 * not have any log messages. 1248 */ 1249 @NotNull() 1250 public final List<String> getLogMessages() 1251 { 1252 return logMessages; 1253 } 1254 1255 1256 1257 /** 1258 * Retrieves a list of the e-mail addresses of the individuals that should be 1259 * notified whenever this task starts running. 1260 * 1261 * @return A list of the e-mail addresses of the individuals that should be 1262 * notified whenever this task starts running, or an empty list if 1263 * there are none. 1264 */ 1265 @NotNull() 1266 public final List<String> getNotifyOnStartAddresses() 1267 { 1268 return notifyOnStart; 1269 } 1270 1271 1272 1273 /** 1274 * Retrieves a list of the e-mail addresses of the individuals that should be 1275 * notified whenever this task completes processing, regardless of whether it 1276 * was successful. 1277 * 1278 * @return A list of the e-mail addresses of the individuals that should be 1279 * notified whenever this task completes processing, or an empty list 1280 * if there are none. 1281 */ 1282 @NotNull() 1283 public final List<String> getNotifyOnCompletionAddresses() 1284 { 1285 return notifyOnCompletion; 1286 } 1287 1288 1289 1290 /** 1291 * Retrieves a list of the e-mail addresses of the individuals that should be 1292 * notified if this task completes successfully. 1293 * 1294 * @return A list of the e-mail addresses of the individuals that should be 1295 * notified if this task completes successfully, or an empty list 1296 * if there are none. 1297 */ 1298 @NotNull() 1299 public final List<String> getNotifyOnSuccessAddresses() 1300 { 1301 return notifyOnSuccess; 1302 } 1303 1304 1305 1306 /** 1307 * Retrieves a list of the e-mail addresses of the individuals that should be 1308 * notified if this task stops processing prematurely due to an error or 1309 * other external action (e.g., server shutdown or administrative cancel). 1310 * 1311 * @return A list of the e-mail addresses of the individuals that should be 1312 * notified if this task stops processing prematurely, or an empty 1313 * list if there are none. 1314 */ 1315 @NotNull() 1316 public final List<String> getNotifyOnErrorAddresses() 1317 { 1318 return notifyOnError; 1319 } 1320 1321 1322 1323 /** 1324 * Retrieves the flag that indicates whether the server should generate an 1325 * administrative alert when this task starts running. 1326 * 1327 * @return {@code true} if the server should send an alert when this task 1328 * starts running, {@code false} if the server should not send an 1329 * alert, or {@code null} if it is not available. 1330 */ 1331 @Nullable() 1332 public final Boolean getAlertOnStart() 1333 { 1334 return alertOnStart; 1335 } 1336 1337 1338 1339 /** 1340 * Retrieves the flag that indicates whether the server should generate an 1341 * administrative alert if this task completes successfully. 1342 * 1343 * @return {@code true} if the server should send an alert if this task 1344 * completes successfully, {@code false} if the server should not 1345 * send an alert, or {@code null} if it is not available. 1346 */ 1347 @Nullable() 1348 public final Boolean getAlertOnSuccess() 1349 { 1350 return alertOnSuccess; 1351 } 1352 1353 1354 1355 /** 1356 * Retrieves the flag that indicates whether the server should generate an 1357 * administrative alert if this task fails to complete successfully. 1358 * 1359 * @return {@code true} if the server should send an alert if this task fails 1360 * to complete successfully, {@code false} if the server should not 1361 * send an alert, or {@code null} if it is not available. 1362 */ 1363 @Nullable() 1364 public final Boolean getAlertOnError() 1365 { 1366 return alertOnError; 1367 } 1368 1369 1370 1371 /** 1372 * Creates an entry that may be added to the Directory Server to create a new 1373 * instance of this task. 1374 * 1375 * @return An entry that may be added to the Directory Server to create a new 1376 * instance of this task. 1377 */ 1378 @NotNull() 1379 public final Entry createTaskEntry() 1380 { 1381 final ArrayList<Attribute> attributes = new ArrayList<>(20); 1382 1383 final ArrayList<String> ocValues = new ArrayList<>(5); 1384 ocValues.add("top"); 1385 ocValues.add(OC_TASK); 1386 ocValues.addAll(getAdditionalObjectClasses()); 1387 attributes.add(new Attribute("objectClass", ocValues)); 1388 1389 attributes.add(new Attribute(ATTR_TASK_ID, taskID)); 1390 1391 attributes.add(new Attribute(ATTR_TASK_CLASS, taskClassName)); 1392 1393 if (scheduledStartTime != null) 1394 { 1395 attributes.add(new Attribute(ATTR_SCHEDULED_START_TIME, 1396 StaticUtils.encodeGeneralizedTime(scheduledStartTime))); 1397 } 1398 1399 if (! dependencyIDs.isEmpty()) 1400 { 1401 attributes.add(new Attribute(ATTR_DEPENDENCY_ID, dependencyIDs)); 1402 } 1403 1404 if (failedDependencyAction != null) 1405 { 1406 attributes.add(new Attribute(ATTR_FAILED_DEPENDENCY_ACTION, 1407 failedDependencyAction.getName())); 1408 } 1409 1410 if (! notifyOnStart.isEmpty()) 1411 { 1412 attributes.add(new Attribute(ATTR_NOTIFY_ON_START, 1413 notifyOnStart)); 1414 } 1415 1416 if (! notifyOnCompletion.isEmpty()) 1417 { 1418 attributes.add(new Attribute(ATTR_NOTIFY_ON_COMPLETION, 1419 notifyOnCompletion)); 1420 } 1421 1422 if (! notifyOnSuccess.isEmpty()) 1423 { 1424 attributes.add(new Attribute(ATTR_NOTIFY_ON_SUCCESS, notifyOnSuccess)); 1425 } 1426 1427 if (! notifyOnError.isEmpty()) 1428 { 1429 attributes.add(new Attribute(ATTR_NOTIFY_ON_ERROR, notifyOnError)); 1430 } 1431 1432 if (alertOnStart != null) 1433 { 1434 attributes.add(new Attribute(ATTR_ALERT_ON_START, 1435 String.valueOf(alertOnStart))); 1436 } 1437 1438 if (alertOnSuccess != null) 1439 { 1440 attributes.add(new Attribute(ATTR_ALERT_ON_SUCCESS, 1441 String.valueOf(alertOnSuccess))); 1442 } 1443 1444 if (alertOnError != null) 1445 { 1446 attributes.add(new Attribute(ATTR_ALERT_ON_ERROR, 1447 String.valueOf(alertOnError))); 1448 } 1449 1450 attributes.addAll(getAdditionalAttributes()); 1451 1452 return new Entry(taskEntryDN, attributes); 1453 } 1454 1455 1456 1457 /** 1458 * Parses the value of the specified attribute as a {@code boolean} value, or 1459 * throws an exception if the value cannot be decoded as a boolean. 1460 * 1461 * @param taskEntry The entry containing the attribute to be parsed. 1462 * @param attributeName The name of the attribute from which the value was 1463 * taken. 1464 * @param defaultValue The default value to use if the provided value 1465 * string is {@code null}. 1466 * 1467 * @return {@code true} if the value string represents a boolean value of 1468 * {@code true}, {@code false} if the value string represents a 1469 * boolean value of {@code false}, or the default value if the value 1470 * string is {@code null}. 1471 * 1472 * @throws TaskException If the provided value string cannot be parsed as a 1473 * {@code boolean} value. 1474 */ 1475 protected static boolean parseBooleanValue(@NotNull final Entry taskEntry, 1476 @NotNull final String attributeName, 1477 final boolean defaultValue) 1478 throws TaskException 1479 { 1480 final String valueString = taskEntry.getAttributeValue(attributeName); 1481 if (valueString == null) 1482 { 1483 return defaultValue; 1484 } 1485 else if (valueString.equalsIgnoreCase("true")) 1486 { 1487 return true; 1488 } 1489 else if (valueString.equalsIgnoreCase("false")) 1490 { 1491 return false; 1492 } 1493 else 1494 { 1495 throw new TaskException(ERR_TASK_CANNOT_PARSE_BOOLEAN.get( 1496 taskEntry.getDN(), valueString, 1497 attributeName)); 1498 } 1499 } 1500 1501 1502 1503 /** 1504 * Parses the values of the specified attribute as a list of strings. 1505 * 1506 * @param taskEntry The entry containing the attribute to be parsed. 1507 * @param attributeName The name of the attribute from which the value was 1508 * taken. 1509 * 1510 * @return A list of strings containing the values of the specified 1511 * attribute, or an empty list if the specified attribute does not 1512 * exist in the target entry. The returned list will be 1513 * unmodifiable. 1514 */ 1515 @NotNull() 1516 protected static List<String> parseStringList(@NotNull final Entry taskEntry, 1517 @NotNull final String attributeName) 1518 { 1519 final String[] valueStrings = taskEntry.getAttributeValues(attributeName); 1520 if (valueStrings == null) 1521 { 1522 return Collections.emptyList(); 1523 } 1524 else 1525 { 1526 return Collections.unmodifiableList(Arrays.asList(valueStrings)); 1527 } 1528 } 1529 1530 1531 1532 /** 1533 * Parses the provided set of values for the associated task property as a 1534 * {@code Boolean}. 1535 * 1536 * @param p The task property with which the values are 1537 * associated. 1538 * @param values The provided values for the task property. 1539 * @param defaultValue The default value to use if the provided object array 1540 * is empty. 1541 * 1542 * @return The parsed {@code Boolean} value. 1543 * 1544 * @throws TaskException If there is a problem with the provided values. 1545 */ 1546 @Nullable() 1547 protected static Boolean parseBoolean(@NotNull final TaskProperty p, 1548 @NotNull final List<Object> values, 1549 @Nullable final Boolean defaultValue) 1550 throws TaskException 1551 { 1552 // Check to see if any values were provided. If not, then it may or may not 1553 // be a problem. 1554 if (values.isEmpty()) 1555 { 1556 if (p.isRequired()) 1557 { 1558 throw new TaskException(ERR_TASK_REQUIRED_PROPERTY_WITHOUT_VALUES.get( 1559 p.getDisplayName())); 1560 } 1561 else 1562 { 1563 return defaultValue; 1564 } 1565 } 1566 1567 // If there were multiple values, then that's always an error. 1568 if (values.size() > 1) 1569 { 1570 throw new TaskException(ERR_TASK_PROPERTY_NOT_MULTIVALUED.get( 1571 p.getDisplayName())); 1572 } 1573 1574 // Make sure that the value can be interpreted as a Boolean. 1575 final Boolean booleanValue; 1576 final Object o = values.get(0); 1577 if (o instanceof Boolean) 1578 { 1579 booleanValue = (Boolean) o; 1580 } 1581 else if (o instanceof String) 1582 { 1583 final String valueStr = (String) o; 1584 if (valueStr.equalsIgnoreCase("true")) 1585 { 1586 booleanValue = Boolean.TRUE; 1587 } 1588 else if (valueStr.equalsIgnoreCase("false")) 1589 { 1590 booleanValue = Boolean.FALSE; 1591 } 1592 else 1593 { 1594 throw new TaskException(ERR_TASK_PROPERTY_VALUE_NOT_BOOLEAN.get( 1595 p.getDisplayName())); 1596 } 1597 } 1598 else 1599 { 1600 throw new TaskException(ERR_TASK_PROPERTY_VALUE_NOT_BOOLEAN.get( 1601 p.getDisplayName())); 1602 } 1603 1604 return booleanValue; 1605 } 1606 1607 1608 1609 /** 1610 * Parses the provided set of values for the associated task property as a 1611 * {@code Date}. 1612 * 1613 * @param p The task property with which the values are 1614 * associated. 1615 * @param values The provided values for the task property. 1616 * @param defaultValue The default value to use if the provided object array 1617 * is empty. 1618 * 1619 * @return The parsed {@code Date} value. 1620 * 1621 * @throws TaskException If there is a problem with the provided values. 1622 */ 1623 @Nullable() 1624 protected static Date parseDate(@NotNull final TaskProperty p, 1625 @NotNull final List<Object> values, 1626 @Nullable final Date defaultValue) 1627 throws TaskException 1628 { 1629 // Check to see if any values were provided. If not, then it may or may not 1630 // be a problem. 1631 if (values.isEmpty()) 1632 { 1633 if (p.isRequired()) 1634 { 1635 throw new TaskException(ERR_TASK_REQUIRED_PROPERTY_WITHOUT_VALUES.get( 1636 p.getDisplayName())); 1637 } 1638 else 1639 { 1640 return defaultValue; 1641 } 1642 } 1643 1644 // If there were multiple values, then that's always an error. 1645 if (values.size() > 1) 1646 { 1647 throw new TaskException(ERR_TASK_PROPERTY_NOT_MULTIVALUED.get( 1648 p.getDisplayName())); 1649 } 1650 1651 // Make sure that the value can be interpreted as a Date. 1652 final Date dateValue; 1653 final Object o = values.get(0); 1654 if (o instanceof Date) 1655 { 1656 dateValue = (Date) o; 1657 } 1658 else if (o instanceof String) 1659 { 1660 try 1661 { 1662 dateValue = StaticUtils.decodeGeneralizedTime((String) o); 1663 } 1664 catch (final ParseException pe) 1665 { 1666 throw new TaskException(ERR_TASK_PROPERTY_VALUE_NOT_DATE.get( 1667 p.getDisplayName()), pe); 1668 } 1669 } 1670 else 1671 { 1672 throw new TaskException(ERR_TASK_PROPERTY_VALUE_NOT_DATE.get( 1673 p.getDisplayName())); 1674 } 1675 1676 // If the task property has a set of allowed values, then make sure that the 1677 // provided value is acceptable. 1678 final Object[] allowedValues = p.getAllowedValues(); 1679 if (allowedValues != null) 1680 { 1681 boolean found = false; 1682 for (final Object allowedValue : allowedValues) 1683 { 1684 if (dateValue.equals(allowedValue)) 1685 { 1686 found = true; 1687 break; 1688 } 1689 } 1690 1691 if (! found) 1692 { 1693 throw new TaskException(ERR_TASK_PROPERTY_VALUE_NOT_ALLOWED.get( 1694 p.getDisplayName(), dateValue.toString())); 1695 } 1696 } 1697 1698 return dateValue; 1699 } 1700 1701 1702 1703 /** 1704 * Parses the provided set of values for the associated task property as a 1705 * {@code Long}. 1706 * 1707 * @param p The task property with which the values are 1708 * associated. 1709 * @param values The provided values for the task property. 1710 * @param defaultValue The default value to use if the provided object array 1711 * is empty. 1712 * 1713 * @return The parsed {@code Long} value. 1714 * 1715 * @throws TaskException If there is a problem with the provided values. 1716 */ 1717 @Nullable() 1718 protected static Long parseLong(@NotNull final TaskProperty p, 1719 @NotNull final List<Object> values, 1720 @Nullable final Long defaultValue) 1721 throws TaskException 1722 { 1723 // Check to see if any values were provided. If not, then it may or may not 1724 // be a problem. 1725 if (values.isEmpty()) 1726 { 1727 if (p.isRequired()) 1728 { 1729 throw new TaskException(ERR_TASK_REQUIRED_PROPERTY_WITHOUT_VALUES.get( 1730 p.getDisplayName())); 1731 } 1732 else 1733 { 1734 return defaultValue; 1735 } 1736 } 1737 1738 // If there were multiple values, then that's always an error. 1739 if (values.size() > 1) 1740 { 1741 throw new TaskException(ERR_TASK_PROPERTY_NOT_MULTIVALUED.get( 1742 p.getDisplayName())); 1743 } 1744 1745 // Make sure that the value can be interpreted as a Long. 1746 final Long longValue; 1747 final Object o = values.get(0); 1748 if (o instanceof Long) 1749 { 1750 longValue = (Long) o; 1751 } 1752 else if (o instanceof Number) 1753 { 1754 longValue = ((Number) o).longValue(); 1755 } 1756 else if (o instanceof String) 1757 { 1758 try 1759 { 1760 longValue = Long.parseLong((String) o); 1761 } 1762 catch (final Exception e) 1763 { 1764 throw new TaskException(ERR_TASK_PROPERTY_VALUE_NOT_LONG.get( 1765 p.getDisplayName()), e); 1766 } 1767 } 1768 else 1769 { 1770 throw new TaskException(ERR_TASK_PROPERTY_VALUE_NOT_LONG.get( 1771 p.getDisplayName())); 1772 } 1773 1774 // If the task property has a set of allowed values, then make sure that the 1775 // provided value is acceptable. 1776 final Object[] allowedValues = p.getAllowedValues(); 1777 if (allowedValues != null) 1778 { 1779 boolean found = false; 1780 for (final Object allowedValue : allowedValues) 1781 { 1782 if (longValue.equals(allowedValue)) 1783 { 1784 found = true; 1785 break; 1786 } 1787 } 1788 1789 if (! found) 1790 { 1791 throw new TaskException(ERR_TASK_PROPERTY_VALUE_NOT_ALLOWED.get( 1792 p.getDisplayName(), longValue.toString())); 1793 } 1794 } 1795 1796 return longValue; 1797 } 1798 1799 1800 1801 /** 1802 * Parses the provided set of values for the associated task property as a 1803 * {@code String}. 1804 * 1805 * @param p The task property with which the values are 1806 * associated. 1807 * @param values The provided values for the task property. 1808 * @param defaultValue The default value to use if the provided object array 1809 * is empty. 1810 * 1811 * @return The parsed {@code String} value. 1812 * 1813 * @throws TaskException If there is a problem with the provided values. 1814 */ 1815 @Nullable() 1816 protected static String parseString(@NotNull final TaskProperty p, 1817 @NotNull final List<Object> values, 1818 @Nullable final String defaultValue) 1819 throws TaskException 1820 { 1821 // Check to see if any values were provided. If not, then it may or may not 1822 // be a problem. 1823 if (values.isEmpty()) 1824 { 1825 if (p.isRequired()) 1826 { 1827 throw new TaskException(ERR_TASK_REQUIRED_PROPERTY_WITHOUT_VALUES.get( 1828 p.getDisplayName())); 1829 } 1830 else 1831 { 1832 return defaultValue; 1833 } 1834 } 1835 1836 // If there were multiple values, then that's always an error. 1837 if (values.size() > 1) 1838 { 1839 throw new TaskException(ERR_TASK_PROPERTY_NOT_MULTIVALUED.get( 1840 p.getDisplayName())); 1841 } 1842 1843 // Make sure that the value is a String. 1844 final String valueStr; 1845 final Object o = values.get(0); 1846 if (o instanceof String) 1847 { 1848 valueStr = (String) o; 1849 } 1850 else if (values.get(0) instanceof CharSequence) 1851 { 1852 valueStr = o.toString(); 1853 } 1854 else 1855 { 1856 throw new TaskException(ERR_TASK_PROPERTY_VALUE_NOT_STRING.get( 1857 p.getDisplayName())); 1858 } 1859 1860 // If the task property has a set of allowed values, then make sure that the 1861 // provided value is acceptable. 1862 final Object[] allowedValues = p.getAllowedValues(); 1863 if (allowedValues != null) 1864 { 1865 boolean found = false; 1866 for (final Object allowedValue : allowedValues) 1867 { 1868 final String s = (String) allowedValue; 1869 if (valueStr.equalsIgnoreCase(s)) 1870 { 1871 found = true; 1872 break; 1873 } 1874 } 1875 1876 if (! found) 1877 { 1878 throw new TaskException(ERR_TASK_PROPERTY_VALUE_NOT_ALLOWED.get( 1879 p.getDisplayName(), valueStr)); 1880 } 1881 } 1882 1883 return valueStr; 1884 } 1885 1886 1887 1888 /** 1889 * Parses the provided set of values for the associated task property as a 1890 * {@code String} array. 1891 * 1892 * @param p The task property with which the values are 1893 * associated. 1894 * @param values The provided values for the task property. 1895 * @param defaultValues The set of default values to use if the provided 1896 * object array is empty. 1897 * 1898 * @return The parsed {@code String} values. 1899 * 1900 * @throws TaskException If there is a problem with the provided values. 1901 */ 1902 @Nullable() 1903 protected static String[] parseStrings(@NotNull final TaskProperty p, 1904 @NotNull final List<Object> values, 1905 @Nullable final String[] defaultValues) 1906 throws TaskException 1907 { 1908 // Check to see if any values were provided. If not, then it may or may not 1909 // be a problem. 1910 if (values.isEmpty()) 1911 { 1912 if (p.isRequired()) 1913 { 1914 throw new TaskException(ERR_TASK_REQUIRED_PROPERTY_WITHOUT_VALUES.get( 1915 p.getDisplayName())); 1916 } 1917 else 1918 { 1919 return defaultValues; 1920 } 1921 } 1922 1923 1924 // Iterate through each of the values and perform appropriate validation for 1925 // them. 1926 final String[] stringValues = new String[values.size()]; 1927 for (int i=0; i < values.size(); i++) 1928 { 1929 final Object o = values.get(i); 1930 1931 // Make sure that the value is a String. 1932 final String valueStr; 1933 if (o instanceof String) 1934 { 1935 valueStr = (String) o; 1936 } 1937 else if (o instanceof CharSequence) 1938 { 1939 valueStr = o.toString(); 1940 } 1941 else 1942 { 1943 throw new TaskException(ERR_TASK_PROPERTY_VALUE_NOT_STRING.get( 1944 p.getDisplayName())); 1945 } 1946 1947 // If the task property has a set of allowed values, then make sure that 1948 // the provided value is acceptable. 1949 final Object[] allowedValues = p.getAllowedValues(); 1950 if (allowedValues != null) 1951 { 1952 boolean found = false; 1953 for (final Object allowedValue : allowedValues) 1954 { 1955 final String s = (String) allowedValue; 1956 if (valueStr.equalsIgnoreCase(s)) 1957 { 1958 found = true; 1959 break; 1960 } 1961 } 1962 1963 if (! found) 1964 { 1965 throw new TaskException(ERR_TASK_PROPERTY_VALUE_NOT_ALLOWED.get( 1966 p.getDisplayName(), valueStr)); 1967 } 1968 } 1969 1970 stringValues[i] = valueStr; 1971 } 1972 1973 return stringValues; 1974 } 1975 1976 1977 1978 /** 1979 * Retrieves a list of the additional object classes (other than the base 1980 * "top" and "ds-task" classes) that should be included when creating new task 1981 * entries of this type. 1982 * 1983 * @return A list of the additional object classes that should be included in 1984 * new task entries of this type, or an empty list if there do not 1985 * need to be any additional classes. 1986 */ 1987 @NotNull() 1988 protected List<String> getAdditionalObjectClasses() 1989 { 1990 return Collections.emptyList(); 1991 } 1992 1993 1994 1995 /** 1996 * Retrieves a list of the additional attributes (other than attributes common 1997 * to all task types) that should be included when creating new task entries 1998 * of this type. 1999 * 2000 * @return A list of the additional attributes that should be included in new 2001 * task entries of this type, or an empty list if there do not need 2002 * to be any additional attributes. 2003 */ 2004 @NotNull() 2005 protected List<Attribute> getAdditionalAttributes() 2006 { 2007 return Collections.emptyList(); 2008 } 2009 2010 2011 2012 /** 2013 * Decodes the provided entry as a scheduled task. An attempt will be made to 2014 * decode the entry as an appropriate subclass if possible, but it will fall 2015 * back to a generic task if it is not possible to decode as a more specific 2016 * task type. 2017 * 2018 * @param entry The entry to be decoded. 2019 * 2020 * @return The decoded task. 2021 * 2022 * @throws TaskException If the provided entry cannot be parsed as a 2023 * scheduled task. 2024 */ 2025 @NotNull() 2026 public static Task decodeTask(@NotNull final Entry entry) 2027 throws TaskException 2028 { 2029 final String taskClass = entry.getAttributeValue(ATTR_TASK_CLASS); 2030 if (taskClass == null) 2031 { 2032 throw new TaskException(ERR_TASK_NO_CLASS.get(entry.getDN())); 2033 } 2034 2035 try 2036 { 2037 if (taskClass.equals(AddSchemaFileTask.ADD_SCHEMA_FILE_TASK_CLASS)) 2038 { 2039 return new AddSchemaFileTask(entry); 2040 } 2041 else if (taskClass.equals(AlertTask.ALERT_TASK_CLASS)) 2042 { 2043 return new AlertTask(entry); 2044 } 2045 else if (taskClass.equals(AuditDataSecurityTask. 2046 AUDIT_DATA_SECURITY_TASK_CLASS)) 2047 { 2048 return new AuditDataSecurityTask(entry); 2049 } 2050 else if (taskClass.equals(BackupTask.BACKUP_TASK_CLASS)) 2051 { 2052 return new BackupTask(entry); 2053 } 2054 else if (taskClass.equals( 2055 CollectSupportDataTask.COLLECT_SUPPORT_DATA_TASK_CLASS)) 2056 { 2057 return new CollectSupportDataTask(entry); 2058 } 2059 else if (taskClass.equals(DelayTask.DELAY_TASK_CLASS)) 2060 { 2061 return new DelayTask(entry); 2062 } 2063 else if (taskClass.equals( 2064 DisconnectClientTask.DISCONNECT_CLIENT_TASK_CLASS)) 2065 { 2066 return new DisconnectClientTask(entry); 2067 } 2068 else if (taskClass.equals(DumpDBDetailsTask.DUMP_DB_DETAILS_TASK_CLASS)) 2069 { 2070 return new DumpDBDetailsTask(entry); 2071 } 2072 else if (taskClass.equals( 2073 EnterLockdownModeTask.ENTER_LOCKDOWN_MODE_TASK_CLASS)) 2074 { 2075 return new EnterLockdownModeTask(entry); 2076 } 2077 else if (taskClass.equals(ExecTask.EXEC_TASK_CLASS)) 2078 { 2079 return new ExecTask(entry); 2080 } 2081 else if (taskClass.equals(ExportTask.EXPORT_TASK_CLASS)) 2082 { 2083 return new ExportTask(entry); 2084 } 2085 else if (taskClass.equals(FileRetentionTask.FILE_RETENTION_TASK_CLASS)) 2086 { 2087 return new FileRetentionTask(entry); 2088 } 2089 else if (taskClass.equals( 2090 GenerateServerProfileTask.GENERATE_SERVER_PROFILE_TASK_CLASS)) 2091 { 2092 return new GenerateServerProfileTask(entry); 2093 } 2094 else if (taskClass.equals(GroovyScriptedTask.GROOVY_SCRIPTED_TASK_CLASS)) 2095 { 2096 return new GroovyScriptedTask(entry); 2097 } 2098 else if (taskClass.equals(ImportTask.IMPORT_TASK_CLASS)) 2099 { 2100 return new ImportTask(entry); 2101 } 2102 else if (taskClass.equals( 2103 LeaveLockdownModeTask.LEAVE_LOCKDOWN_MODE_TASK_CLASS)) 2104 { 2105 return new LeaveLockdownModeTask(entry); 2106 } 2107 else if (taskClass.equals( 2108 PopulateComposedAttributeValuesTask. 2109 POPULATE_COMPOSED_ATTRIBUTE_VALUES_TASK_CLASS)) 2110 { 2111 return new PopulateComposedAttributeValuesTask(entry); 2112 } 2113 else if (taskClass.equals(RebuildTask.REBUILD_TASK_CLASS)) 2114 { 2115 return new RebuildTask(entry); 2116 } 2117 else if (taskClass.equals( 2118 ReEncodeEntriesTask.RE_ENCODE_ENTRIES_TASK_CLASS)) 2119 { 2120 return new ReEncodeEntriesTask(entry); 2121 } 2122 else if (taskClass.equals(RefreshEncryptionSettingsTask. 2123 REFRESH_ENCRYPTION_SETTINGS_TASK_CLASS)) 2124 { 2125 return new RefreshEncryptionSettingsTask(entry); 2126 } 2127 else if (taskClass.equals( 2128 ReloadGlobalIndexTask.RELOAD_GLOBAL_INDEX_TASK_CLASS)) 2129 { 2130 return new ReloadGlobalIndexTask(entry); 2131 } 2132 else if (taskClass.equals( 2133 ReloadHTTPConnectionHandlerCertificatesTask. 2134 RELOAD_HTTP_CONNECTION_HANDLER_CERTIFICATES_TASK_CLASS)) 2135 { 2136 return new ReloadHTTPConnectionHandlerCertificatesTask(entry); 2137 } 2138 else if (taskClass.equals( 2139 RemoveAttributeTypeTask.REMOVE_ATTRIBUTE_TYPE_TASK_CLASS)) 2140 { 2141 return new RemoveAttributeTypeTask(entry); 2142 } 2143 else if (taskClass.equals( 2144 RemoveObjectClassTask.REMOVE_OBJECT_CLASS_TASK_CLASS)) 2145 { 2146 return new RemoveObjectClassTask(entry); 2147 } 2148 else if (taskClass.equals(RestoreTask.RESTORE_TASK_CLASS)) 2149 { 2150 return new RestoreTask(entry); 2151 } 2152 else if (taskClass.equals(RotateLogTask.ROTATE_LOG_TASK_CLASS)) 2153 { 2154 return new RotateLogTask(entry); 2155 } 2156 else if (taskClass.equals(SearchTask.SEARCH_TASK_CLASS)) 2157 { 2158 return new SearchTask(entry); 2159 } 2160 else if (taskClass.equals(ShutdownTask.SHUTDOWN_TASK_CLASS)) 2161 { 2162 return new ShutdownTask(entry); 2163 } 2164 else if (taskClass.equals(SynchronizeEncryptionSettingsTask. 2165 SYNCHRONIZE_ENCRYPTION_SETTINGS_TASK_CLASS)) 2166 { 2167 return new SynchronizeEncryptionSettingsTask(entry); 2168 } 2169 else if (taskClass.equals(ThirdPartyTask.THIRD_PARTY_TASK_CLASS)) 2170 { 2171 return new ThirdPartyTask(entry); 2172 } 2173 } 2174 catch (final TaskException te) 2175 { 2176 Debug.debugException(te); 2177 } 2178 2179 return new Task(entry); 2180 } 2181 2182 2183 2184 /** 2185 * Retrieves a list of task properties that may be provided when scheduling 2186 * any type of task. This includes: 2187 * <UL> 2188 * <LI>The task ID</LI> 2189 * <LI>The scheduled start time</LI> 2190 * <LI>The task IDs of any tasks on which this task is dependent</LI> 2191 * <LI>The action to take for this task if any of its dependencies fail</LI> 2192 * <LI>The addresses of users to notify when this task starts</LI> 2193 * <LI>The addresses of users to notify when this task completes</LI> 2194 * <LI>The addresses of users to notify if this task succeeds</LI> 2195 * <LI>The addresses of users to notify if this task fails</LI> 2196 * <LI>A flag indicating whether to generate an alert when the task 2197 * starts</LI> 2198 * <LI>A flag indicating whether to generate an alert when the task 2199 * succeeds</LI> 2200 * <LI>A flag indicating whether to generate an alert when the task 2201 * fails</LI> 2202 * </UL> 2203 * 2204 * @return A list of task properties that may be provided when scheduling any 2205 * type of task. 2206 */ 2207 @NotNull() 2208 public static List<TaskProperty> getCommonTaskProperties() 2209 { 2210 final List<TaskProperty> taskList = Arrays.asList( 2211 PROPERTY_TASK_ID, 2212 PROPERTY_SCHEDULED_START_TIME, 2213 PROPERTY_DEPENDENCY_ID, 2214 PROPERTY_FAILED_DEPENDENCY_ACTION, 2215 PROPERTY_NOTIFY_ON_START, 2216 PROPERTY_NOTIFY_ON_COMPLETION, 2217 PROPERTY_NOTIFY_ON_SUCCESS, 2218 PROPERTY_NOTIFY_ON_ERROR, 2219 PROPERTY_ALERT_ON_START, 2220 PROPERTY_ALERT_ON_SUCCESS, 2221 PROPERTY_ALERT_ON_ERROR); 2222 2223 return Collections.unmodifiableList(taskList); 2224 } 2225 2226 2227 2228 /** 2229 * Retrieves a list of task-specific properties that may be provided when 2230 * scheduling a task of this type. This method should be overridden by 2231 * subclasses in order to provide an appropriate set of properties. 2232 * 2233 * @return A list of task-specific properties that may be provided when 2234 * scheduling a task of this type. 2235 */ 2236 @NotNull() 2237 public List<TaskProperty> getTaskSpecificProperties() 2238 { 2239 return Collections.emptyList(); 2240 } 2241 2242 2243 2244 /** 2245 * Retrieves the values of the task properties for this task. The data type 2246 * of the values will vary based on the data type of the corresponding task 2247 * property and may be one of the following types: {@code Boolean}, 2248 * {@code Date}, {@code Long}, or {@code String}. Task properties which do 2249 * not have any values will be included in the map with an empty value list. 2250 * <BR><BR> 2251 * Note that subclasses which have additional task properties should override 2252 * this method and return a map which contains both the property values from 2253 * this class (obtained from {@code super.getTaskPropertyValues()} and the 2254 * values of their own task-specific properties. 2255 * 2256 * @return A map of the task property values for this task. 2257 */ 2258 @NotNull() 2259 public Map<TaskProperty,List<Object>> getTaskPropertyValues() 2260 { 2261 final LinkedHashMap<TaskProperty,List<Object>> props = 2262 new LinkedHashMap<>(StaticUtils.computeMapCapacity(20)); 2263 2264 props.put(PROPERTY_TASK_ID, 2265 Collections.<Object>singletonList(taskID)); 2266 2267 if (scheduledStartTime == null) 2268 { 2269 props.put(PROPERTY_SCHEDULED_START_TIME, Collections.emptyList()); 2270 } 2271 else 2272 { 2273 props.put(PROPERTY_SCHEDULED_START_TIME, 2274 Collections.<Object>singletonList(scheduledStartTime)); 2275 } 2276 2277 props.put(PROPERTY_DEPENDENCY_ID, 2278 Collections.<Object>unmodifiableList(dependencyIDs)); 2279 2280 if (failedDependencyAction == null) 2281 { 2282 props.put(PROPERTY_FAILED_DEPENDENCY_ACTION, Collections.emptyList()); 2283 } 2284 else 2285 { 2286 props.put(PROPERTY_FAILED_DEPENDENCY_ACTION, 2287 Collections.<Object>singletonList(failedDependencyAction.getName())); 2288 } 2289 2290 props.put(PROPERTY_NOTIFY_ON_START, 2291 Collections.<Object>unmodifiableList(notifyOnStart)); 2292 2293 props.put(PROPERTY_NOTIFY_ON_COMPLETION, 2294 Collections.<Object>unmodifiableList(notifyOnCompletion)); 2295 2296 props.put(PROPERTY_NOTIFY_ON_SUCCESS, 2297 Collections.<Object>unmodifiableList(notifyOnSuccess)); 2298 2299 props.put(PROPERTY_NOTIFY_ON_ERROR, 2300 Collections.<Object>unmodifiableList(notifyOnError)); 2301 2302 if (alertOnStart != null) 2303 { 2304 props.put(PROPERTY_ALERT_ON_START, 2305 Collections.<Object>singletonList(alertOnStart)); 2306 } 2307 2308 if (alertOnSuccess != null) 2309 { 2310 props.put(PROPERTY_ALERT_ON_SUCCESS, 2311 Collections.<Object>singletonList(alertOnSuccess)); 2312 } 2313 2314 if (alertOnError!= null) 2315 { 2316 props.put(PROPERTY_ALERT_ON_ERROR, 2317 Collections.<Object>singletonList(alertOnError)); 2318 } 2319 2320 return Collections.unmodifiableMap(props); 2321 } 2322 2323 2324 2325 /** 2326 * Retrieves a string representation of this task. 2327 * 2328 * @return A string representation of this task. 2329 */ 2330 @Override() 2331 @NotNull() 2332 public final String toString() 2333 { 2334 final StringBuilder buffer = new StringBuilder(); 2335 toString(buffer); 2336 return buffer.toString(); 2337 } 2338 2339 2340 2341 /** 2342 * Appends a string representation of this task to the provided buffer. 2343 * 2344 * @param buffer The buffer to which the string representation should be 2345 * provided. 2346 */ 2347 public final void toString(@NotNull final StringBuilder buffer) 2348 { 2349 buffer.append("Task(name='"); 2350 buffer.append(getTaskName()); 2351 buffer.append("', className='"); 2352 buffer.append(taskClassName); 2353 buffer.append(", properties={"); 2354 2355 boolean added = false; 2356 for (final Map.Entry<TaskProperty,List<Object>> e : 2357 getTaskPropertyValues().entrySet()) 2358 { 2359 if (added) 2360 { 2361 buffer.append(", "); 2362 } 2363 else 2364 { 2365 added = true; 2366 } 2367 2368 buffer.append(e.getKey().getAttributeName()); 2369 buffer.append("={"); 2370 2371 final Iterator<Object> iterator = e.getValue().iterator(); 2372 while (iterator.hasNext()) 2373 { 2374 buffer.append('\''); 2375 buffer.append(String.valueOf(iterator.next())); 2376 buffer.append('\''); 2377 2378 if (iterator.hasNext()) 2379 { 2380 buffer.append(','); 2381 } 2382 } 2383 2384 buffer.append('}'); 2385 } 2386 2387 buffer.append("})"); 2388 } 2389}