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