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.NotExtensible; 040import com.unboundid.util.ThreadSafety; 041import com.unboundid.util.ThreadSafetyLevel; 042 043import static com.unboundid.ldap.sdk.unboundidds.tasks.TaskMessages.*; 044import static com.unboundid.util.Debug.*; 045import static com.unboundid.util.StaticUtils.*; 046import static com.unboundid.util.Validator.*; 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 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 Alcatel-Lucent 8661 060 * server products. These classes provide support for proprietary 061 * functionality or for external specifications that are not considered stable 062 * or mature enough to be guaranteed to work in an interoperable way with 063 * 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 static final String ATTR_ACTUAL_START_TIME = "ds-task-actual-start-time"; 130 131 132 133 /** 134 * The name of the attribute used to hold the completion time for scheduled 135 * tasks. 136 */ 137 static final String ATTR_COMPLETION_TIME = "ds-task-completion-time"; 138 139 140 141 /** 142 * The name of the attribute used to hold the task IDs for tasks on which a 143 * scheduled task is dependent. 144 */ 145 static final String ATTR_DEPENDENCY_ID = "ds-task-dependency-id"; 146 147 148 149 /** 150 * The name of the attribute used to indicate what action to take if one of 151 * the dependencies for a task failed to complete successfully. 152 */ 153 static final String ATTR_FAILED_DEPENDENCY_ACTION = 154 "ds-task-failed-dependency-action"; 155 156 157 158 /** 159 * The name of the attribute used to hold the log messages for scheduled 160 * tasks. 161 */ 162 static final String ATTR_LOG_MESSAGE = "ds-task-log-message"; 163 164 165 166 /** 167 * The name of the attribute used to hold the e-mail addresses of the users 168 * that should be notified whenever a scheduled task completes, regardless of 169 * success or failure. 170 */ 171 static final String ATTR_NOTIFY_ON_COMPLETION = 172 "ds-task-notify-on-completion"; 173 174 175 176 /** 177 * The name of the attribute used to hold the e-mail addresses of the users 178 * that should be notified if a scheduled task fails to complete successfully. 179 */ 180 static final String ATTR_NOTIFY_ON_ERROR = "ds-task-notify-on-error"; 181 182 183 184 /** 185 * The name of the attribute used to hold the scheduled start time for 186 * scheduled tasks. 187 */ 188 static final String ATTR_SCHEDULED_START_TIME = 189 "ds-task-scheduled-start-time"; 190 191 192 193 /** 194 * The name of the attribute used to hold the name of the class that provides 195 * the logic for scheduled tasks. 196 */ 197 static final String ATTR_TASK_CLASS = "ds-task-class-name"; 198 199 200 201 /** 202 * The name of the attribute used to hold the task ID for scheduled tasks. 203 */ 204 static final String ATTR_TASK_ID = "ds-task-id"; 205 206 207 208 /** 209 * The name of the attribute used to hold the current state for scheduled 210 * tasks. 211 */ 212 static final String ATTR_TASK_STATE = "ds-task-state"; 213 214 215 216 /** 217 * The name of the base object class for scheduled tasks. 218 */ 219 static final String OC_TASK = "ds-task"; 220 221 222 223 /** 224 * The DN of the entry below which scheduled tasks reside. 225 */ 226 static final String SCHEDULED_TASKS_BASE_DN = 227 "cn=Scheduled Tasks,cn=tasks"; 228 229 230 231 /** 232 * The task property that will be used for the task ID. 233 */ 234 static final TaskProperty PROPERTY_TASK_ID = 235 new TaskProperty(ATTR_TASK_ID, INFO_DISPLAY_NAME_TASK_ID.get(), 236 INFO_DESCRIPTION_TASK_ID.get(), String.class, false, 237 false, true); 238 239 240 241 /** 242 * The task property that will be used for the scheduled start time. 243 */ 244 static final TaskProperty PROPERTY_SCHEDULED_START_TIME = 245 new TaskProperty(ATTR_SCHEDULED_START_TIME, 246 INFO_DISPLAY_NAME_SCHEDULED_START_TIME.get(), 247 INFO_DESCRIPTION_SCHEDULED_START_TIME.get(), Date.class, 248 false, false, true); 249 250 251 252 /** 253 * The task property that will be used for the set of dependency IDs. 254 */ 255 static final TaskProperty PROPERTY_DEPENDENCY_ID = 256 new TaskProperty(ATTR_DEPENDENCY_ID, 257 INFO_DISPLAY_NAME_DEPENDENCY_ID.get(), 258 INFO_DESCRIPTION_DEPENDENCY_ID.get(), String.class, 259 false, true, true); 260 261 262 263 /** 264 * The task property that will be used for the failed dependency action. 265 */ 266 static final TaskProperty PROPERTY_FAILED_DEPENDENCY_ACTION = 267 new TaskProperty(ATTR_FAILED_DEPENDENCY_ACTION, 268 INFO_DISPLAY_NAME_FAILED_DEPENDENCY_ACTION.get(), 269 INFO_DESCRIPTION_FAILED_DEPENDENCY_ACTION.get(), 270 String.class, false, false, true, 271 new String[] 272 { 273 FailedDependencyAction.CANCEL.getName(), 274 FailedDependencyAction.DISABLE.getName(), 275 FailedDependencyAction.PROCESS.getName() 276 }); 277 278 279 280 /** 281 * The task property that will be used for the notify on completion addresses. 282 */ 283 static final TaskProperty PROPERTY_NOTIFY_ON_COMPLETION = 284 new TaskProperty(ATTR_NOTIFY_ON_COMPLETION, 285 INFO_DISPLAY_NAME_NOTIFY_ON_COMPLETION.get(), 286 INFO_DESCRIPTION_NOTIFY_ON_COMPLETION.get(), 287 String.class, false, true, true); 288 289 290 291 /** 292 * The task property that will be used for the notify on error addresses. 293 */ 294 static final TaskProperty PROPERTY_NOTIFY_ON_ERROR = 295 new TaskProperty(ATTR_NOTIFY_ON_ERROR, 296 INFO_DISPLAY_NAME_NOTIFY_ON_ERROR.get(), 297 INFO_DESCRIPTION_NOTIFY_ON_ERROR.get(), 298 String.class, false, true, true); 299 300 301 302 /** 303 * The serial version UID for this serializable class. 304 */ 305 private static final long serialVersionUID = -3521189553470479032L; 306 307 308 309 // The time that this task actually started. 310 private final Date actualStartTime; 311 312 // The time that this task completed. 313 private final Date completionTime; 314 315 // The time that this task was scheduled to start. 316 private final Date scheduledStartTime; 317 318 // The entry from which this task was decoded. 319 private final Entry taskEntry; 320 321 // The failed dependency action for this task. 322 private final FailedDependencyAction failedDependencyAction; 323 324 // The set of task IDs of the tasks on which this task is dependent. 325 private final List<String> dependencyIDs; 326 327 // The set of log messages for this task. 328 private final List<String> logMessages; 329 330 // The set of e-mail addresses of users that should be notified when the task 331 // processing is complete. 332 private final List<String> notifyOnCompletion; 333 334 // The set of e-mail addresses of users that should be notified if task 335 // processing completes with an error. 336 private final List<String> notifyOnError; 337 338 // The fully-qualified name of the task class. 339 private final String taskClassName; 340 341 // The DN of the entry for this task. 342 private final String taskEntryDN; 343 344 // The task ID for this task. 345 private final String taskID; 346 347 // The current state for this task. 348 private final TaskState taskState; 349 350 351 352 /** 353 * Creates a new uninitialized task instance which should only be used for 354 * obtaining general information about this task, including the task name, 355 * description, and supported properties. Attempts to use a task created with 356 * this constructor for any other reason will likely fail. 357 */ 358 protected Task() 359 { 360 actualStartTime = null; 361 completionTime = null; 362 scheduledStartTime = null; 363 taskEntry = null; 364 failedDependencyAction = null; 365 dependencyIDs = null; 366 logMessages = null; 367 notifyOnCompletion = null; 368 notifyOnError = null; 369 taskClassName = null; 370 taskEntryDN = null; 371 taskID = null; 372 taskState = null; 373 } 374 375 376 377 /** 378 * Creates a new unscheduled task with the specified task ID and class name. 379 * 380 * @param taskID The task ID to use for this task. If it is 381 * {@code null} then a UUID will be generated for use 382 * as the task ID. 383 * @param taskClassName The fully-qualified name of the Java class that 384 * provides the logic for the task. It must not be 385 * {@code null}. 386 */ 387 public Task(final String taskID, final String taskClassName) 388 { 389 this(taskID, taskClassName, null, null, null, null, null); 390 } 391 392 393 394 /** 395 * Creates a new unscheduled task with the provided information. 396 * 397 * @param taskID The task ID to use for this task. 398 * @param taskClassName The fully-qualified name of the Java class 399 * that provides the logic for the task. It 400 * must not be {@code null}. 401 * @param scheduledStartTime The time that this task should start 402 * running. 403 * @param dependencyIDs The list of task IDs that will be required 404 * to complete before this task will be 405 * eligible to start. 406 * @param failedDependencyAction Indicates what action should be taken if 407 * any of the dependencies for this task do 408 * not complete successfully. 409 * @param notifyOnCompletion The list of e-mail addresses of individuals 410 * that should be notified when this task 411 * completes. 412 * @param notifyOnError The list of e-mail addresses of individuals 413 * that should be notified if this task does 414 * not complete successfully. 415 */ 416 public Task(final String taskID, final String taskClassName, 417 final Date scheduledStartTime, final List<String> dependencyIDs, 418 final FailedDependencyAction failedDependencyAction, 419 final List<String> notifyOnCompletion, 420 final List<String> notifyOnError) 421 { 422 ensureNotNull(taskClassName); 423 424 this.taskClassName = taskClassName; 425 this.scheduledStartTime = scheduledStartTime; 426 this.failedDependencyAction = failedDependencyAction; 427 428 if (taskID == null) 429 { 430 this.taskID = UUID.randomUUID().toString(); 431 } 432 else 433 { 434 this.taskID = taskID; 435 } 436 437 if (dependencyIDs == null) 438 { 439 this.dependencyIDs = Collections.emptyList(); 440 } 441 else 442 { 443 this.dependencyIDs = Collections.unmodifiableList(dependencyIDs); 444 } 445 446 if (notifyOnCompletion == null) 447 { 448 this.notifyOnCompletion = Collections.emptyList(); 449 } 450 else 451 { 452 this.notifyOnCompletion = 453 Collections.unmodifiableList(notifyOnCompletion); 454 } 455 456 if (notifyOnError == null) 457 { 458 this.notifyOnError = Collections.emptyList(); 459 } 460 else 461 { 462 this.notifyOnError = Collections.unmodifiableList(notifyOnError); 463 } 464 465 taskEntry = null; 466 taskEntryDN = ATTR_TASK_ID + '=' + this.taskID + ',' + 467 SCHEDULED_TASKS_BASE_DN; 468 actualStartTime = null; 469 completionTime = null; 470 logMessages = Collections.emptyList(); 471 taskState = TaskState.UNSCHEDULED; 472 } 473 474 475 476 /** 477 * Creates a new task from the provided entry. 478 * 479 * @param entry The entry to use to create this task. 480 * 481 * @throws TaskException If the provided entry cannot be parsed as a 482 * scheduled task. 483 */ 484 public Task(final Entry entry) 485 throws TaskException 486 { 487 taskEntry = entry; 488 taskEntryDN = entry.getDN(); 489 490 // Ensure that the task entry has the appropriate object class for a 491 // scheduled task. 492 if (! entry.hasObjectClass(OC_TASK)) 493 { 494 throw new TaskException(ERR_TASK_MISSING_OC.get(taskEntryDN)); 495 } 496 497 498 // Get the task ID. It must be present. 499 taskID = entry.getAttributeValue(ATTR_TASK_ID); 500 if (taskID == null) 501 { 502 throw new TaskException(ERR_TASK_NO_ID.get(taskEntryDN)); 503 } 504 505 506 // Get the task class name. It must be present. 507 taskClassName = entry.getAttributeValue(ATTR_TASK_CLASS); 508 if (taskClassName == null) 509 { 510 throw new TaskException(ERR_TASK_NO_CLASS.get(taskEntryDN)); 511 } 512 513 514 // Get the task state. If it is not present, then assume "unscheduled". 515 final String stateStr = entry.getAttributeValue(ATTR_TASK_STATE); 516 if (stateStr == null) 517 { 518 taskState = TaskState.UNSCHEDULED; 519 } 520 else 521 { 522 taskState = TaskState.forName(stateStr); 523 if (taskState == null) 524 { 525 throw new TaskException(ERR_TASK_INVALID_STATE.get(taskEntryDN, 526 stateStr)); 527 } 528 } 529 530 531 // Get the scheduled start time. It may be absent. 532 String timestamp = entry.getAttributeValue(ATTR_SCHEDULED_START_TIME); 533 if (timestamp == null) 534 { 535 scheduledStartTime = null; 536 } 537 else 538 { 539 try 540 { 541 scheduledStartTime = decodeGeneralizedTime(timestamp); 542 } 543 catch (final ParseException pe) 544 { 545 debugException(pe); 546 throw new TaskException(ERR_TASK_CANNOT_PARSE_SCHEDULED_START_TIME.get( 547 taskEntryDN, timestamp, pe.getMessage()), 548 pe); 549 } 550 } 551 552 553 // Get the actual start time. It may be absent. 554 timestamp = entry.getAttributeValue(ATTR_ACTUAL_START_TIME); 555 if (timestamp == null) 556 { 557 actualStartTime = null; 558 } 559 else 560 { 561 try 562 { 563 actualStartTime = decodeGeneralizedTime(timestamp); 564 } 565 catch (final ParseException pe) 566 { 567 debugException(pe); 568 throw new TaskException(ERR_TASK_CANNOT_PARSE_ACTUAL_START_TIME.get( 569 taskEntryDN, timestamp, pe.getMessage()), 570 pe); 571 } 572 } 573 574 575 // Get the completion start time. It may be absent. 576 timestamp = entry.getAttributeValue(ATTR_COMPLETION_TIME); 577 if (timestamp == null) 578 { 579 completionTime = null; 580 } 581 else 582 { 583 try 584 { 585 completionTime = decodeGeneralizedTime(timestamp); 586 } 587 catch (final ParseException pe) 588 { 589 debugException(pe); 590 throw new TaskException(ERR_TASK_CANNOT_PARSE_COMPLETION_TIME.get( 591 taskEntryDN, timestamp, pe.getMessage()), 592 pe); 593 } 594 } 595 596 597 // Get the failed dependency action for this task. It may be absent. 598 final String name = entry.getAttributeValue(ATTR_FAILED_DEPENDENCY_ACTION); 599 if (name == null) 600 { 601 failedDependencyAction = null; 602 } 603 else 604 { 605 failedDependencyAction = FailedDependencyAction.forName(name); 606 } 607 608 609 // Get the dependent task IDs for this task. It may be absent. 610 dependencyIDs = parseStringList(entry, ATTR_DEPENDENCY_ID); 611 612 613 // Get the log messages for this task. It may be absent. 614 logMessages = parseStringList(entry, ATTR_LOG_MESSAGE); 615 616 617 // Get the notify on completion addresses for this task. It may be absent. 618 notifyOnCompletion = parseStringList(entry, ATTR_NOTIFY_ON_COMPLETION); 619 620 621 // Get the notify on error addresses for this task. It may be absent. 622 notifyOnError = parseStringList(entry, ATTR_NOTIFY_ON_ERROR); 623 } 624 625 626 627 /** 628 * Creates a new task from the provided set of task properties. 629 * 630 * @param taskClassName The fully-qualified name of the Java class that 631 * provides the logic for the task. It must not be 632 * {@code null}. 633 * @param properties The set of task properties and their corresponding 634 * values to use for the task. It must not be 635 * {@code null}. 636 * 637 * @throws TaskException If the provided set of properties cannot be used to 638 * create a valid scheduled task. 639 */ 640 public Task(final String taskClassName, 641 final Map<TaskProperty,List<Object>> properties) 642 throws TaskException 643 { 644 ensureNotNull(taskClassName, properties); 645 646 this.taskClassName = taskClassName; 647 648 String idStr = UUID.randomUUID().toString(); 649 Date sst = null; 650 String[] depIDs = NO_STRINGS; 651 FailedDependencyAction fda = FailedDependencyAction.CANCEL; 652 String[] noc = NO_STRINGS; 653 String[] noe = NO_STRINGS; 654 655 for (final Map.Entry<TaskProperty,List<Object>> entry : 656 properties.entrySet()) 657 { 658 final TaskProperty p = entry.getKey(); 659 final String attrName = p.getAttributeName(); 660 final List<Object> values = entry.getValue(); 661 662 if (attrName.equalsIgnoreCase(ATTR_TASK_ID)) 663 { 664 idStr = parseString(p, values, idStr); 665 } 666 else if (attrName.equalsIgnoreCase(ATTR_SCHEDULED_START_TIME)) 667 { 668 sst = parseDate(p, values, sst); 669 } 670 else if (attrName.equalsIgnoreCase(ATTR_DEPENDENCY_ID)) 671 { 672 depIDs = parseStrings(p, values, depIDs); 673 } 674 else if (attrName.equalsIgnoreCase(ATTR_FAILED_DEPENDENCY_ACTION)) 675 { 676 fda = FailedDependencyAction.forName( 677 parseString(p, values, fda.getName())); 678 } 679 else if (attrName.equalsIgnoreCase(ATTR_NOTIFY_ON_COMPLETION)) 680 { 681 noc = parseStrings(p, values, noc); 682 } 683 else if (attrName.equalsIgnoreCase(ATTR_NOTIFY_ON_ERROR)) 684 { 685 noe = parseStrings(p, values, noe); 686 } 687 } 688 689 taskID = idStr; 690 scheduledStartTime = sst; 691 dependencyIDs = Collections.unmodifiableList(Arrays.asList(depIDs)); 692 failedDependencyAction = fda; 693 notifyOnCompletion = Collections.unmodifiableList(Arrays.asList(noc)); 694 notifyOnError = Collections.unmodifiableList(Arrays.asList(noe)); 695 taskEntry = null; 696 taskEntryDN = ATTR_TASK_ID + '=' + taskID + ',' + SCHEDULED_TASKS_BASE_DN; 697 actualStartTime = null; 698 completionTime = null; 699 logMessages = Collections.emptyList(); 700 taskState = TaskState.UNSCHEDULED; 701 } 702 703 704 705 /** 706 * Retrieves a list containing instances of the available task types. The 707 * provided task instances will may only be used for obtaining general 708 * information about the task (e.g., name, description, and supported 709 * properties). 710 * 711 * @return A list containing instances of the available task types. 712 */ 713 public static List<Task> getAvailableTaskTypes() 714 { 715 final List<Task> taskList = Arrays.asList( 716 new AddSchemaFileTask(), 717 new AlertTask(), 718 new AuditDataSecurityTask(), 719 new BackupTask(), 720 new DisconnectClientTask(), 721 new DumpDBDetailsTask(), 722 new EnterLockdownModeTask(), 723 new ExportTask(), 724 new GroovyScriptedTask(), 725 new ImportTask(), 726 new LeaveLockdownModeTask(), 727 new RebuildTask(), 728 new ReEncodeEntriesTask(), 729 new RefreshEncryptionSettingsTask(), 730 new ReloadGlobalIndexTask(), 731 new RestoreTask(), 732 new RotateLogTask(), 733 new SearchTask(), 734 new ShutdownTask(), 735 new SynchronizeEncryptionSettingsTask(), 736 new ThirdPartyTask()); 737 738 return Collections.unmodifiableList(taskList); 739 } 740 741 742 743 /** 744 * Retrieves a human-readable name for this task. 745 * 746 * @return A human-readable name for this task. 747 */ 748 public String getTaskName() 749 { 750 return INFO_TASK_NAME_GENERIC.get(); 751 } 752 753 754 755 /** 756 * Retrieves a human-readable description for this task. 757 * 758 * @return A human-readable description for this task. 759 */ 760 public String getTaskDescription() 761 { 762 return INFO_TASK_DESCRIPTION_GENERIC.get(); 763 } 764 765 766 767 /** 768 * Retrieves the entry from which this task was decoded, if available. Note 769 * that although the entry is not immutable, changes made to it will not be 770 * reflected in this task. 771 * 772 * @return The entry from which this task was decoded, or {@code null} if 773 * this task was not created from an existing entry. 774 */ 775 protected final Entry getTaskEntry() 776 { 777 return taskEntry; 778 } 779 780 781 782 /** 783 * Retrieves the DN of the entry in which this scheduled task is defined. 784 * 785 * @return The DN of the entry in which this scheduled task is defined. 786 */ 787 public final String getTaskEntryDN() 788 { 789 return taskEntryDN; 790 } 791 792 793 794 /** 795 * Retrieves the task ID for this task. 796 * 797 * @return The task ID for this task. 798 */ 799 public final String getTaskID() 800 { 801 return taskID; 802 } 803 804 805 806 /** 807 * Retrieves the fully-qualified name of the Java class that provides the 808 * logic for this class. 809 * 810 * @return The fully-qualified name of the Java class that provides the logic 811 * for this task. 812 */ 813 public final String getTaskClassName() 814 { 815 return taskClassName; 816 } 817 818 819 820 /** 821 * Retrieves the current state for this task. 822 * 823 * @return The current state for this task. 824 */ 825 public final TaskState getState() 826 { 827 return taskState; 828 } 829 830 831 832 /** 833 * Indicates whether this task is currently pending execution. 834 * 835 * @return {@code true} if this task is currently pending execution, or 836 * {@code false} if not. 837 */ 838 public final boolean isPending() 839 { 840 return taskState.isPending(); 841 } 842 843 844 845 /** 846 * Indicates whether this task is currently running. 847 * 848 * @return {@code true} if this task is currently running, or {@code false} 849 * if not. 850 */ 851 public final boolean isRunning() 852 { 853 return taskState.isRunning(); 854 } 855 856 857 858 /** 859 * Indicates whether this task has completed execution. 860 * 861 * @return {@code true} if this task has completed execution, or 862 * {@code false} if not. 863 */ 864 public final boolean isCompleted() 865 { 866 return taskState.isCompleted(); 867 } 868 869 870 871 /** 872 * Retrieves the time that this task is/was scheduled to start running. 873 * 874 * @return The time that this task is/was scheduled to start running, or 875 * {@code null} if that is not available and therefore the task 876 * should start running as soon as all dependencies have been met. 877 */ 878 public final Date getScheduledStartTime() 879 { 880 return scheduledStartTime; 881 } 882 883 884 885 /** 886 * Retrieves the time that this task actually started running. 887 * 888 * @return The time that this task actually started running, or {@code null} 889 * if that is not available (e.g., because the task has not yet 890 * started). 891 */ 892 public final Date getActualStartTime() 893 { 894 return actualStartTime; 895 } 896 897 898 899 /** 900 * Retrieves the time that this task completed. 901 * 902 * @return The time that this task completed, or {@code null} if it has not 903 * yet completed. 904 */ 905 public final Date getCompletionTime() 906 { 907 return completionTime; 908 } 909 910 911 912 /** 913 * Retrieves a list of the task IDs for tasks that must complete before this 914 * task will be eligible to start. 915 * 916 * @return A list of the task IDs for tasks that must complete before this 917 * task will be eligible to start, or an empty list if this task does 918 * not have any dependencies. 919 */ 920 public final List<String> getDependencyIDs() 921 { 922 return dependencyIDs; 923 } 924 925 926 927 /** 928 * Retrieves the failed dependency action for this task, which indicates the 929 * behavior that it should exhibit if any of its dependencies encounter a 930 * failure. 931 * 932 * @return The failed dependency action for this task, or {@code null} if it 933 * is not available. 934 */ 935 public final FailedDependencyAction getFailedDependencyAction() 936 { 937 return failedDependencyAction; 938 } 939 940 941 942 /** 943 * Retrieves the log messages for this task. Note that if the task has 944 * generated a very large number of log messages, then only a portion of the 945 * most recent messages may be available. 946 * 947 * @return The log messages for this task, or an empty list if this task does 948 * not have any log messages. 949 */ 950 public final List<String> getLogMessages() 951 { 952 return logMessages; 953 } 954 955 956 957 /** 958 * Retrieves a list of the e-mail addresses of the individuals that should be 959 * notified whenever this task completes processing, regardless of whether it 960 * was successful. 961 * 962 * @return A list of the e-mail addresses of the individuals that should be 963 * notified whenever this task completes processing, or an empty list 964 * if there are none. 965 */ 966 public final List<String> getNotifyOnCompletionAddresses() 967 { 968 return notifyOnCompletion; 969 } 970 971 972 973 /** 974 * Retrieves a list of the e-mail addresses of the individuals that should be 975 * notified if this task stops processing prematurely due to an error or 976 * other external action (e.g., server shutdown or administrative cancel). 977 * 978 * @return A list of the e-mail addresses of the individuals that should be 979 * notified if this task stops processing prematurely, or an empty 980 * list if there are none. 981 */ 982 public final List<String> getNotifyOnErrorAddresses() 983 { 984 return notifyOnError; 985 } 986 987 988 989 /** 990 * Creates an entry that may be added to the Directory Server to create a new 991 * instance of this task. 992 * 993 * @return An entry that may be added to the Directory Server to create a new 994 * instance of this task. 995 */ 996 public final Entry createTaskEntry() 997 { 998 final ArrayList<Attribute> attributes = new ArrayList<Attribute>(); 999 1000 final ArrayList<String> ocValues = new ArrayList<String>(5); 1001 ocValues.add("top"); 1002 ocValues.add(OC_TASK); 1003 ocValues.addAll(getAdditionalObjectClasses()); 1004 attributes.add(new Attribute("objectClass", ocValues)); 1005 1006 attributes.add(new Attribute(ATTR_TASK_ID, taskID)); 1007 1008 attributes.add(new Attribute(ATTR_TASK_CLASS, taskClassName)); 1009 1010 if (scheduledStartTime != null) 1011 { 1012 attributes.add(new Attribute(ATTR_SCHEDULED_START_TIME, 1013 encodeGeneralizedTime(scheduledStartTime))); 1014 } 1015 1016 if (! dependencyIDs.isEmpty()) 1017 { 1018 attributes.add(new Attribute(ATTR_DEPENDENCY_ID, dependencyIDs)); 1019 } 1020 1021 if (failedDependencyAction != null) 1022 { 1023 attributes.add(new Attribute(ATTR_FAILED_DEPENDENCY_ACTION, 1024 failedDependencyAction.getName())); 1025 } 1026 1027 if (! notifyOnCompletion.isEmpty()) 1028 { 1029 attributes.add(new Attribute(ATTR_NOTIFY_ON_COMPLETION, 1030 notifyOnCompletion)); 1031 } 1032 1033 if (! notifyOnError.isEmpty()) 1034 { 1035 attributes.add(new Attribute(ATTR_NOTIFY_ON_ERROR, notifyOnError)); 1036 } 1037 1038 attributes.addAll(getAdditionalAttributes()); 1039 1040 return new Entry(taskEntryDN, attributes); 1041 } 1042 1043 1044 1045 /** 1046 * Parses the value of the specified attribute as a {@code boolean} value, or 1047 * throws an exception if the value cannot be decoded as a boolean. 1048 * 1049 * @param taskEntry The entry containing the attribute to be parsed. 1050 * @param attributeName The name of the attribute from which the value was 1051 * taken. 1052 * @param defaultValue The default value to use if the provided value 1053 * string is {@code null}. 1054 * 1055 * @return {@code true} if the value string represents a boolean value of 1056 * {@code true}, {@code false} if the value string represents a 1057 * boolean value of {@code false}, or the default value if the value 1058 * string is {@code null}. 1059 * 1060 * @throws TaskException If the provided value string cannot be parsed as a 1061 * {@code boolean} value. 1062 */ 1063 protected static boolean parseBooleanValue(final Entry taskEntry, 1064 final String attributeName, 1065 final boolean defaultValue) 1066 throws TaskException 1067 { 1068 final String valueString = taskEntry.getAttributeValue(attributeName); 1069 if (valueString == null) 1070 { 1071 return defaultValue; 1072 } 1073 else if (valueString.equalsIgnoreCase("true")) 1074 { 1075 return true; 1076 } 1077 else if (valueString.equalsIgnoreCase("false")) 1078 { 1079 return false; 1080 } 1081 else 1082 { 1083 throw new TaskException(ERR_TASK_CANNOT_PARSE_BOOLEAN.get( 1084 taskEntry.getDN(), valueString, 1085 attributeName)); 1086 } 1087 } 1088 1089 1090 1091 /** 1092 * Parses the values of the specified attribute as a list of strings. 1093 * 1094 * @param taskEntry The entry containing the attribute to be parsed. 1095 * @param attributeName The name of the attribute from which the value was 1096 * taken. 1097 * 1098 * @return A list of strings containing the values of the specified 1099 * attribute, or an empty list if the specified attribute does not 1100 * exist in the target entry. The returned list will be 1101 * unmodifiable. 1102 */ 1103 protected static List<String> parseStringList(final Entry taskEntry, 1104 final String attributeName) 1105 { 1106 final String[] valueStrings = taskEntry.getAttributeValues(attributeName); 1107 if (valueStrings == null) 1108 { 1109 return Collections.emptyList(); 1110 } 1111 else 1112 { 1113 return Collections.unmodifiableList(Arrays.asList(valueStrings)); 1114 } 1115 } 1116 1117 1118 1119 /** 1120 * Parses the provided set of values for the associated task property as a 1121 * {@code Boolean}. 1122 * 1123 * @param p The task property with which the values are 1124 * associated. 1125 * @param values The provided values for the task property. 1126 * @param defaultValue The default value to use if the provided object array 1127 * is empty. 1128 * 1129 * @return The parsed {@code Boolean} value. 1130 * 1131 * @throws TaskException If there is a problem with the provided values. 1132 */ 1133 protected static Boolean parseBoolean(final TaskProperty p, 1134 final List<Object> values, 1135 final Boolean defaultValue) 1136 throws TaskException 1137 { 1138 // Check to see if any values were provided. If not, then it may or may not 1139 // be a problem. 1140 if (values.isEmpty()) 1141 { 1142 if (p.isRequired()) 1143 { 1144 throw new TaskException(ERR_TASK_REQUIRED_PROPERTY_WITHOUT_VALUES.get( 1145 p.getDisplayName())); 1146 } 1147 else 1148 { 1149 return defaultValue; 1150 } 1151 } 1152 1153 // If there were multiple values, then that's always an error. 1154 if (values.size() > 1) 1155 { 1156 throw new TaskException(ERR_TASK_PROPERTY_NOT_MULTIVALUED.get( 1157 p.getDisplayName())); 1158 } 1159 1160 // Make sure that the value can be interpreted as a Boolean. 1161 final Boolean booleanValue; 1162 final Object o = values.get(0); 1163 if (o instanceof Boolean) 1164 { 1165 booleanValue = (Boolean) o; 1166 } 1167 else if (o instanceof String) 1168 { 1169 final String valueStr = (String) o; 1170 if (valueStr.equalsIgnoreCase("true")) 1171 { 1172 booleanValue = Boolean.TRUE; 1173 } 1174 else if (valueStr.equalsIgnoreCase("false")) 1175 { 1176 booleanValue = Boolean.FALSE; 1177 } 1178 else 1179 { 1180 throw new TaskException(ERR_TASK_PROPERTY_VALUE_NOT_BOOLEAN.get( 1181 p.getDisplayName())); 1182 } 1183 } 1184 else 1185 { 1186 throw new TaskException(ERR_TASK_PROPERTY_VALUE_NOT_BOOLEAN.get( 1187 p.getDisplayName())); 1188 } 1189 1190 return booleanValue; 1191 } 1192 1193 1194 1195 /** 1196 * Parses the provided set of values for the associated task property as a 1197 * {@code Date}. 1198 * 1199 * @param p The task property with which the values are 1200 * associated. 1201 * @param values The provided values for the task property. 1202 * @param defaultValue The default value to use if the provided object array 1203 * is empty. 1204 * 1205 * @return The parsed {@code Date} value. 1206 * 1207 * @throws TaskException If there is a problem with the provided values. 1208 */ 1209 protected static Date parseDate(final TaskProperty p, 1210 final List<Object> values, 1211 final Date defaultValue) 1212 throws TaskException 1213 { 1214 // Check to see if any values were provided. If not, then it may or may not 1215 // be a problem. 1216 if (values.isEmpty()) 1217 { 1218 if (p.isRequired()) 1219 { 1220 throw new TaskException(ERR_TASK_REQUIRED_PROPERTY_WITHOUT_VALUES.get( 1221 p.getDisplayName())); 1222 } 1223 else 1224 { 1225 return defaultValue; 1226 } 1227 } 1228 1229 // If there were multiple values, then that's always an error. 1230 if (values.size() > 1) 1231 { 1232 throw new TaskException(ERR_TASK_PROPERTY_NOT_MULTIVALUED.get( 1233 p.getDisplayName())); 1234 } 1235 1236 // Make sure that the value can be interpreted as a Date. 1237 final Date dateValue; 1238 final Object o = values.get(0); 1239 if (o instanceof Date) 1240 { 1241 dateValue = (Date) o; 1242 } 1243 else if (o instanceof String) 1244 { 1245 try 1246 { 1247 dateValue = decodeGeneralizedTime((String) o); 1248 } 1249 catch (final ParseException pe) 1250 { 1251 throw new TaskException(ERR_TASK_PROPERTY_VALUE_NOT_DATE.get( 1252 p.getDisplayName()), pe); 1253 } 1254 } 1255 else 1256 { 1257 throw new TaskException(ERR_TASK_PROPERTY_VALUE_NOT_DATE.get( 1258 p.getDisplayName())); 1259 } 1260 1261 // If the task property has a set of allowed values, then make sure that the 1262 // provided value is acceptable. 1263 final Object[] allowedValues = p.getAllowedValues(); 1264 if (allowedValues != null) 1265 { 1266 boolean found = false; 1267 for (final Object allowedValue : allowedValues) 1268 { 1269 if (dateValue.equals(allowedValue)) 1270 { 1271 found = true; 1272 break; 1273 } 1274 } 1275 1276 if (! found) 1277 { 1278 throw new TaskException(ERR_TASK_PROPERTY_VALUE_NOT_ALLOWED.get( 1279 p.getDisplayName(), dateValue.toString())); 1280 } 1281 } 1282 1283 return dateValue; 1284 } 1285 1286 1287 1288 /** 1289 * Parses the provided set of values for the associated task property as a 1290 * {@code Long}. 1291 * 1292 * @param p The task property with which the values are 1293 * associated. 1294 * @param values The provided values for the task property. 1295 * @param defaultValue The default value to use if the provided object array 1296 * is empty. 1297 * 1298 * @return The parsed {@code Long} value. 1299 * 1300 * @throws TaskException If there is a problem with the provided values. 1301 */ 1302 protected static Long parseLong(final TaskProperty p, 1303 final List<Object> values, 1304 final Long defaultValue) 1305 throws TaskException 1306 { 1307 // Check to see if any values were provided. If not, then it may or may not 1308 // be a problem. 1309 if (values.isEmpty()) 1310 { 1311 if (p.isRequired()) 1312 { 1313 throw new TaskException(ERR_TASK_REQUIRED_PROPERTY_WITHOUT_VALUES.get( 1314 p.getDisplayName())); 1315 } 1316 else 1317 { 1318 return defaultValue; 1319 } 1320 } 1321 1322 // If there were multiple values, then that's always an error. 1323 if (values.size() > 1) 1324 { 1325 throw new TaskException(ERR_TASK_PROPERTY_NOT_MULTIVALUED.get( 1326 p.getDisplayName())); 1327 } 1328 1329 // Make sure that the value can be interpreted as a Long. 1330 final Long longValue; 1331 final Object o = values.get(0); 1332 if (o instanceof Long) 1333 { 1334 longValue = (Long) o; 1335 } 1336 else if (o instanceof Number) 1337 { 1338 longValue = ((Number) o).longValue(); 1339 } 1340 else if (o instanceof String) 1341 { 1342 try 1343 { 1344 longValue = Long.parseLong((String) o); 1345 } 1346 catch (final Exception e) 1347 { 1348 throw new TaskException(ERR_TASK_PROPERTY_VALUE_NOT_LONG.get( 1349 p.getDisplayName()), e); 1350 } 1351 } 1352 else 1353 { 1354 throw new TaskException(ERR_TASK_PROPERTY_VALUE_NOT_LONG.get( 1355 p.getDisplayName())); 1356 } 1357 1358 // If the task property has a set of allowed values, then make sure that the 1359 // provided value is acceptable. 1360 final Object[] allowedValues = p.getAllowedValues(); 1361 if (allowedValues != null) 1362 { 1363 boolean found = false; 1364 for (final Object allowedValue : allowedValues) 1365 { 1366 if (longValue.equals(allowedValue)) 1367 { 1368 found = true; 1369 break; 1370 } 1371 } 1372 1373 if (! found) 1374 { 1375 throw new TaskException(ERR_TASK_PROPERTY_VALUE_NOT_ALLOWED.get( 1376 p.getDisplayName(), longValue.toString())); 1377 } 1378 } 1379 1380 return longValue; 1381 } 1382 1383 1384 1385 /** 1386 * Parses the provided set of values for the associated task property as a 1387 * {@code String}. 1388 * 1389 * @param p The task property with which the values are 1390 * associated. 1391 * @param values The provided values for the task property. 1392 * @param defaultValue The default value to use if the provided object array 1393 * is empty. 1394 * 1395 * @return The parsed {@code String} value. 1396 * 1397 * @throws TaskException If there is a problem with the provided values. 1398 */ 1399 protected static String parseString(final TaskProperty p, 1400 final List<Object> values, 1401 final String defaultValue) 1402 throws TaskException 1403 { 1404 // Check to see if any values were provided. If not, then it may or may not 1405 // be a problem. 1406 if (values.isEmpty()) 1407 { 1408 if (p.isRequired()) 1409 { 1410 throw new TaskException(ERR_TASK_REQUIRED_PROPERTY_WITHOUT_VALUES.get( 1411 p.getDisplayName())); 1412 } 1413 else 1414 { 1415 return defaultValue; 1416 } 1417 } 1418 1419 // If there were multiple values, then that's always an error. 1420 if (values.size() > 1) 1421 { 1422 throw new TaskException(ERR_TASK_PROPERTY_NOT_MULTIVALUED.get( 1423 p.getDisplayName())); 1424 } 1425 1426 // Make sure that the value is a String. 1427 final String valueStr; 1428 final Object o = values.get(0); 1429 if (o instanceof String) 1430 { 1431 valueStr = (String) o; 1432 } 1433 else if (values.get(0) instanceof CharSequence) 1434 { 1435 valueStr = o.toString(); 1436 } 1437 else 1438 { 1439 throw new TaskException(ERR_TASK_PROPERTY_VALUE_NOT_STRING.get( 1440 p.getDisplayName())); 1441 } 1442 1443 // If the task property has a set of allowed values, then make sure that the 1444 // provided value is acceptable. 1445 final Object[] allowedValues = p.getAllowedValues(); 1446 if (allowedValues != null) 1447 { 1448 boolean found = false; 1449 for (final Object allowedValue : allowedValues) 1450 { 1451 final String s = (String) allowedValue; 1452 if (valueStr.equalsIgnoreCase(s)) 1453 { 1454 found = true; 1455 break; 1456 } 1457 } 1458 1459 if (! found) 1460 { 1461 throw new TaskException(ERR_TASK_PROPERTY_VALUE_NOT_ALLOWED.get( 1462 p.getDisplayName(), valueStr)); 1463 } 1464 } 1465 1466 return valueStr; 1467 } 1468 1469 1470 1471 /** 1472 * Parses the provided set of values for the associated task property as a 1473 * {@code String} array. 1474 * 1475 * @param p The task property with which the values are 1476 * associated. 1477 * @param values The provided values for the task property. 1478 * @param defaultValues The set of default values to use if the provided 1479 * object array is empty. 1480 * 1481 * @return The parsed {@code String} values. 1482 * 1483 * @throws TaskException If there is a problem with the provided values. 1484 */ 1485 protected static String[] parseStrings(final TaskProperty p, 1486 final List<Object> values, 1487 final String[] defaultValues) 1488 throws TaskException 1489 { 1490 // Check to see if any values were provided. If not, then it may or may not 1491 // be a problem. 1492 if (values.isEmpty()) 1493 { 1494 if (p.isRequired()) 1495 { 1496 throw new TaskException(ERR_TASK_REQUIRED_PROPERTY_WITHOUT_VALUES.get( 1497 p.getDisplayName())); 1498 } 1499 else 1500 { 1501 return defaultValues; 1502 } 1503 } 1504 1505 1506 // Iterate through each of the values and perform appropriate validation for 1507 // them. 1508 final String[] stringValues = new String[values.size()]; 1509 for (int i=0; i < values.size(); i++) 1510 { 1511 final Object o = values.get(i); 1512 1513 // Make sure that the value is a String. 1514 final String valueStr; 1515 if (o instanceof String) 1516 { 1517 valueStr = (String) o; 1518 } 1519 else if (o instanceof CharSequence) 1520 { 1521 valueStr = o.toString(); 1522 } 1523 else 1524 { 1525 throw new TaskException(ERR_TASK_PROPERTY_VALUE_NOT_STRING.get( 1526 p.getDisplayName())); 1527 } 1528 1529 // If the task property has a set of allowed values, then make sure that 1530 // the provided value is acceptable. 1531 final Object[] allowedValues = p.getAllowedValues(); 1532 if (allowedValues != null) 1533 { 1534 boolean found = false; 1535 for (final Object allowedValue : allowedValues) 1536 { 1537 final String s = (String) allowedValue; 1538 if (valueStr.equalsIgnoreCase(s)) 1539 { 1540 found = true; 1541 break; 1542 } 1543 } 1544 1545 if (! found) 1546 { 1547 throw new TaskException(ERR_TASK_PROPERTY_VALUE_NOT_ALLOWED.get( 1548 p.getDisplayName(), valueStr)); 1549 } 1550 } 1551 1552 stringValues[i] = valueStr; 1553 } 1554 1555 return stringValues; 1556 } 1557 1558 1559 1560 /** 1561 * Retrieves a list of the additional object classes (other than the base 1562 * "top" and "ds-task" classes) that should be included when creating new task 1563 * entries of this type. 1564 * 1565 * @return A list of the additional object classes that should be included in 1566 * new task entries of this type, or an empty list if there do not 1567 * need to be any additional classes. 1568 */ 1569 protected List<String> getAdditionalObjectClasses() 1570 { 1571 return Collections.emptyList(); 1572 } 1573 1574 1575 1576 /** 1577 * Retrieves a list of the additional attributes (other than attributes common 1578 * to all task types) that should be included when creating new task entries 1579 * of this type. 1580 * 1581 * @return A list of the additional attributes that should be included in new 1582 * task entries of this type, or an empty list if there do not need 1583 * to be any additional attributes. 1584 */ 1585 protected List<Attribute> getAdditionalAttributes() 1586 { 1587 return Collections.emptyList(); 1588 } 1589 1590 1591 1592 /** 1593 * Decodes the provided entry as a scheduled task. An attempt will be made to 1594 * decode the entry as an appropriate subclass if possible, but it will fall 1595 * back to a generic task if it is not possible to decode as a more specific 1596 * task type. 1597 * 1598 * @param entry The entry to be decoded. 1599 * 1600 * @return The decoded task. 1601 * 1602 * @throws TaskException If the provided entry cannot be parsed as a 1603 * scheduled task. 1604 */ 1605 public static Task decodeTask(final Entry entry) 1606 throws TaskException 1607 { 1608 final String taskClass = entry.getAttributeValue(ATTR_TASK_CLASS); 1609 if (taskClass == null) 1610 { 1611 throw new TaskException(ERR_TASK_NO_CLASS.get(entry.getDN())); 1612 } 1613 1614 try 1615 { 1616 if (taskClass.equals(AddSchemaFileTask.ADD_SCHEMA_FILE_TASK_CLASS)) 1617 { 1618 return new AddSchemaFileTask(entry); 1619 } 1620 else if (taskClass.equals(AlertTask.ALERT_TASK_CLASS)) 1621 { 1622 return new AlertTask(entry); 1623 } 1624 else if (taskClass.equals(AuditDataSecurityTask. 1625 AUDIT_DATA_SECURITY_TASK_CLASS)) 1626 { 1627 return new AuditDataSecurityTask(entry); 1628 } 1629 else if (taskClass.equals(BackupTask.BACKUP_TASK_CLASS)) 1630 { 1631 return new BackupTask(entry); 1632 } 1633 else if (taskClass.equals( 1634 DisconnectClientTask.DISCONNECT_CLIENT_TASK_CLASS)) 1635 { 1636 return new DisconnectClientTask(entry); 1637 } 1638 else if (taskClass.equals(DumpDBDetailsTask.DUMP_DB_DETAILS_TASK_CLASS)) 1639 { 1640 return new DumpDBDetailsTask(entry); 1641 } 1642 else if (taskClass.equals( 1643 EnterLockdownModeTask.ENTER_LOCKDOWN_MODE_TASK_CLASS)) 1644 { 1645 return new EnterLockdownModeTask(entry); 1646 } 1647 else if (taskClass.equals(ExportTask.EXPORT_TASK_CLASS)) 1648 { 1649 return new ExportTask(entry); 1650 } 1651 else if (taskClass.equals(GroovyScriptedTask.GROOVY_SCRIPTED_TASK_CLASS)) 1652 { 1653 return new GroovyScriptedTask(entry); 1654 } 1655 else if (taskClass.equals(ImportTask.IMPORT_TASK_CLASS)) 1656 { 1657 return new ImportTask(entry); 1658 } 1659 else if (taskClass.equals( 1660 LeaveLockdownModeTask.LEAVE_LOCKDOWN_MODE_TASK_CLASS)) 1661 { 1662 return new LeaveLockdownModeTask(entry); 1663 } 1664 else if (taskClass.equals(RebuildTask.REBUILD_TASK_CLASS)) 1665 { 1666 return new RebuildTask(entry); 1667 } 1668 else if (taskClass.equals( 1669 ReEncodeEntriesTask.RE_ENCODE_ENTRIES_TASK_CLASS)) 1670 { 1671 return new ReEncodeEntriesTask(entry); 1672 } 1673 else if (taskClass.equals(RefreshEncryptionSettingsTask. 1674 REFRESH_ENCRYPTION_SETTINGS_TASK_CLASS)) 1675 { 1676 return new RefreshEncryptionSettingsTask(entry); 1677 } 1678 else if (taskClass.equals( 1679 ReloadGlobalIndexTask.RELOAD_GLOBAL_INDEX_TASK_CLASS)) 1680 { 1681 return new ReloadGlobalIndexTask(entry); 1682 } 1683 else if (taskClass.equals(RestoreTask.RESTORE_TASK_CLASS)) 1684 { 1685 return new RestoreTask(entry); 1686 } 1687 else if (taskClass.equals(RotateLogTask.ROTATE_LOG_TASK_CLASS)) 1688 { 1689 return new RotateLogTask(entry); 1690 } 1691 else if (taskClass.equals(SearchTask.SEARCH_TASK_CLASS)) 1692 { 1693 return new SearchTask(entry); 1694 } 1695 else if (taskClass.equals(ShutdownTask.SHUTDOWN_TASK_CLASS)) 1696 { 1697 return new ShutdownTask(entry); 1698 } 1699 else if (taskClass.equals(SynchronizeEncryptionSettingsTask. 1700 SYNCHRONIZE_ENCRYPTION_SETTINGS_TASK_CLASS)) 1701 { 1702 return new SynchronizeEncryptionSettingsTask(entry); 1703 } 1704 else if (taskClass.equals(ThirdPartyTask.THIRD_PARTY_TASK_CLASS)) 1705 { 1706 return new ThirdPartyTask(entry); 1707 } 1708 } 1709 catch (final TaskException te) 1710 { 1711 debugException(te); 1712 } 1713 1714 return new Task(entry); 1715 } 1716 1717 1718 1719 /** 1720 * Retrieves a list of task properties that may be provided when scheduling 1721 * any type of task. This includes: 1722 * <UL> 1723 * <LI>The task ID</LI> 1724 * <LI>The scheduled start time</LI> 1725 * <LI>The task IDs of any tasks on which this task is dependent</LI> 1726 * <LI>The action to take for this task if any of its dependencies fail</LI> 1727 * <LI>The addresses of users to notify when this task completes</LI> 1728 * <LI>The addresses of users to notify if this task fails</LI> 1729 * </UL> 1730 * 1731 * @return A list of task properties that may be provided when scheduling any 1732 * type of task. 1733 */ 1734 public static List<TaskProperty> getCommonTaskProperties() 1735 { 1736 final List<TaskProperty> taskList = Arrays.asList( 1737 PROPERTY_TASK_ID, 1738 PROPERTY_SCHEDULED_START_TIME, 1739 PROPERTY_DEPENDENCY_ID, 1740 PROPERTY_FAILED_DEPENDENCY_ACTION, 1741 PROPERTY_NOTIFY_ON_COMPLETION, 1742 PROPERTY_NOTIFY_ON_ERROR); 1743 1744 return Collections.unmodifiableList(taskList); 1745 } 1746 1747 1748 1749 /** 1750 * Retrieves a list of task-specific properties that may be provided when 1751 * scheduling a task of this type. This method should be overridden by 1752 * subclasses in order to provide an appropriate set of properties. 1753 * 1754 * @return A list of task-specific properties that may be provided when 1755 * scheduling a task of this type. 1756 */ 1757 public List<TaskProperty> getTaskSpecificProperties() 1758 { 1759 return Collections.emptyList(); 1760 } 1761 1762 1763 1764 /** 1765 * Retrieves the values of the task properties for this task. The data type 1766 * of the values will vary based on the data type of the corresponding task 1767 * property and may be one of the following types: {@code Boolean}, 1768 * {@code Date}, {@code Long}, or {@code String}. Task properties which do 1769 * not have any values will be included in the map with an empty value list. 1770 * <BR><BR> 1771 * Note that subclasses which have additional task properties should override 1772 * this method and return a map which contains both the property values from 1773 * this class (obtained from {@code super.getTaskPropertyValues()} and the 1774 * values of their own task-specific properties. 1775 * 1776 * @return A map of the task property values for this task. 1777 */ 1778 public Map<TaskProperty,List<Object>> getTaskPropertyValues() 1779 { 1780 final LinkedHashMap<TaskProperty,List<Object>> props = 1781 new LinkedHashMap<TaskProperty,List<Object>>(); 1782 1783 props.put(PROPERTY_TASK_ID, 1784 Collections.<Object>unmodifiableList(Arrays.asList(taskID))); 1785 1786 if (scheduledStartTime == null) 1787 { 1788 props.put(PROPERTY_SCHEDULED_START_TIME, Collections.emptyList()); 1789 } 1790 else 1791 { 1792 props.put(PROPERTY_SCHEDULED_START_TIME, 1793 Collections.<Object>unmodifiableList(Arrays.asList( 1794 scheduledStartTime))); 1795 } 1796 1797 props.put(PROPERTY_DEPENDENCY_ID, 1798 Collections.<Object>unmodifiableList(dependencyIDs)); 1799 1800 if (failedDependencyAction == null) 1801 { 1802 props.put(PROPERTY_FAILED_DEPENDENCY_ACTION, Collections.emptyList()); 1803 } 1804 else 1805 { 1806 props.put(PROPERTY_FAILED_DEPENDENCY_ACTION, 1807 Collections.<Object>unmodifiableList(Arrays.asList( 1808 failedDependencyAction.getName()))); 1809 } 1810 1811 props.put(PROPERTY_NOTIFY_ON_COMPLETION, 1812 Collections.<Object>unmodifiableList(notifyOnCompletion)); 1813 1814 props.put(PROPERTY_NOTIFY_ON_ERROR, 1815 Collections.<Object>unmodifiableList(notifyOnError)); 1816 1817 return Collections.unmodifiableMap(props); 1818 } 1819 1820 1821 1822 /** 1823 * Retrieves a string representation of this task. 1824 * 1825 * @return A string representation of this task. 1826 */ 1827 @Override() 1828 public final String toString() 1829 { 1830 final StringBuilder buffer = new StringBuilder(); 1831 toString(buffer); 1832 return buffer.toString(); 1833 } 1834 1835 1836 1837 /** 1838 * Appends a string representation of this task to the provided buffer. 1839 * 1840 * @param buffer The buffer to which the string representation should be 1841 * provided. 1842 */ 1843 public final void toString(final StringBuilder buffer) 1844 { 1845 buffer.append("Task(name='"); 1846 buffer.append(getTaskName()); 1847 buffer.append("', className='"); 1848 buffer.append(taskClassName); 1849 buffer.append(", properties={"); 1850 1851 boolean added = false; 1852 for (final Map.Entry<TaskProperty,List<Object>> e : 1853 getTaskPropertyValues().entrySet()) 1854 { 1855 if (added) 1856 { 1857 buffer.append(", "); 1858 } 1859 else 1860 { 1861 added = true; 1862 } 1863 1864 buffer.append(e.getKey().getAttributeName()); 1865 buffer.append("={"); 1866 1867 final Iterator<Object> iterator = e.getValue().iterator(); 1868 while (iterator.hasNext()) 1869 { 1870 buffer.append('\''); 1871 buffer.append(String.valueOf(iterator.next())); 1872 buffer.append('\''); 1873 1874 if (iterator.hasNext()) 1875 { 1876 buffer.append(','); 1877 } 1878 } 1879 1880 buffer.append('}'); 1881 } 1882 1883 buffer.append("})"); 1884 } 1885}