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