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