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.util.ArrayList;
026import java.util.Arrays;
027import java.util.Collections;
028import java.util.Date;
029import java.util.LinkedHashMap;
030import java.util.List;
031import java.util.Map;
032
033import com.unboundid.ldap.sdk.Attribute;
034import com.unboundid.ldap.sdk.Entry;
035import com.unboundid.util.NotMutable;
036import com.unboundid.util.StaticUtils;
037import com.unboundid.util.ThreadSafety;
038import com.unboundid.util.ThreadSafetyLevel;
039import com.unboundid.util.args.DurationArgument;
040
041import static com.unboundid.ldap.sdk.unboundidds.tasks.TaskMessages.*;
042import static com.unboundid.util.Validator.*;
043
044
045
046/**
047 * This class defines a Directory Server task that can be used to back up one or
048 * more Directory Server backends.
049 * <BR>
050 * <BLOCKQUOTE>
051 *   <B>NOTE:</B>  This class, and other classes within the
052 *   {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
053 *   supported for use against Ping Identity, UnboundID, and Alcatel-Lucent 8661
054 *   server products.  These classes provide support for proprietary
055 *   functionality or for external specifications that are not considered stable
056 *   or mature enough to be guaranteed to work in an interoperable way with
057 *   other types of LDAP servers.
058 * </BLOCKQUOTE>
059 * <BR>
060 * The properties that are available for use with this type of task include:
061 * <UL>
062 *   <LI>The path to the directory in which the backup should be placed.  If
063 *       multiple backends are to be backed up at once, then this should be the
064 *       parent of the backup directories for each backend.  This must be
065 *       provided when scheduling this task.</LI>
066 *   <LI>The backend IDs of the backends to archive.  If this is not provided,
067 *       then the server will attempt to back up all supported backends.</LI>
068 *   <LI>The backup ID to use for the backup.  If this is not provided, then the
069 *       server will generate a backup ID.</LI>
070 *   <LI>A flag that indicates whether the backup should be an incremental
071 *       backup (if the backend supports that capability) or a full backup.</LI>
072 *   <LI>The backup ID of the existing backup on which the incremental backup
073 *       should be based.  If this is not provided and an incremental backup
074 *       is to be performed, then it will be based on the most recent backup in
075 *       the backup directory.</LI>
076 *   <LI>A flag that indicates whether to compress the contents of the
077 *       backup.</LI>
078 *   <LI>A flag that indicates whether to encrypt the contents of the
079 *       backup.</LI>
080 *   <LI>A flag that indicates whether to hash the contents of the backup to use
081 *       as a checksum for verifying the integrity of the backup.</LI>
082 *   <LI>A flag that indicates whether to sign the backup hash in order to
083 *       prevent anyone from tampering with it.</LI>
084 *   <LI>The path to a file containing a passphrase to use to generate the
085 *       encryption key.</LI>
086 *   <LI>The ID of the encryption settings definition to use to generate the
087 *       encryption key.</LI>
088 *   <LI>The maximum rate in megabytes per second at which the backup should be
089 *       written.</LI>
090 *   <LI>The minimum number of previous full backups to retain.</LI>
091 *   <LI>The minimum age of previous full backups to retain.</LI>
092 * </UL>
093
094 */
095@NotMutable()
096@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
097public final class BackupTask
098       extends Task
099{
100  /**
101   * The fully-qualified name of the Java class that is used for the backup
102   * task.
103   */
104  static final String BACKUP_TASK_CLASS =
105       "com.unboundid.directory.server.tasks.BackupTask";
106
107
108
109  /**
110   * The name of the attribute used to specify backend IDs of the backends to
111   * archive.
112   */
113  private static final String ATTR_BACKEND_ID = "ds-task-backup-backend-id";
114
115
116
117  /**
118   * The name of the attribute used to indicate whether to back up the contents
119   * of all supported backends.
120   */
121  private static final String ATTR_BACKUP_ALL = "ds-task-backup-all";
122
123
124
125  /**
126   * The name of the attribute used to specify the path to the directory in
127   * which the backup is to be written.
128   */
129  private static final String ATTR_BACKUP_DIRECTORY =
130       "ds-backup-directory-path";
131
132
133
134  /**
135   * The name of the attribute used to specify the backup ID for the backup.
136   */
137  private static final String ATTR_BACKUP_ID = "ds-backup-id";
138
139
140
141  /**
142   * The name of the attribute used to indicate whether to compress the backup.
143   */
144  private static final String ATTR_COMPRESS = "ds-task-backup-compress";
145
146
147
148  /**
149   * The name of the attribute used to indicate whether to encrypt the backup.
150   */
151  private static final String ATTR_ENCRYPT = "ds-task-backup-encrypt";
152
153
154
155  /**
156   * The name of the attribute used to specify the path to a file that contains
157   * the passphrase to use to generate the encryption key.
158   */
159  private static final String ATTR_ENCRYPTION_PASSPHRASE_FILE =
160       "ds-task-backup-encryption-passphrase-file";
161
162
163
164  /**
165   * The name of the attribute used to specify the path to a file that contains
166   * the ID of the encryption settings definition to use to generate the
167   * encryption key.
168   */
169  private static final String ATTR_ENCRYPTION_SETTINGS_DEFINITION_ID =
170       "ds-task-backup-encryption-settings-definition-id";
171
172
173
174  /**
175   * The name of the attribute used to indicate whether to create a hash of the
176   * backup.
177   */
178  private static final String ATTR_HASH = "ds-task-backup-hash";
179
180
181
182  /**
183   * The name of the attribute used to indicate whether to perform an
184   * incremental backup rather than a full backup.
185   */
186  private static final String ATTR_INCREMENTAL = "ds-task-backup-incremental";
187
188
189
190  /**
191   * The name of the attribute used to specify the backup ID of the backup
192   * on which to base the incremental backup.
193   */
194  private static final String ATTR_INCREMENTAL_BASE_ID =
195       "ds-task-backup-incremental-base-id";
196
197
198
199  /**
200   * The name of the attribute used to specify the maximum backup write rate in
201   * megabytes per second.
202   */
203  private static final String ATTR_MAX_MEGABYTES_PER_SECOND =
204       "ds-task-backup-max-megabytes-per-second";
205
206
207
208  /**
209   * The name of the attribute used to specify the minimum age of previous full
210   * backups to retain.
211   */
212  private static final String ATTR_RETAIN_PREVIOUS_FULL_BACKUP_AGE =
213       "ds-task-backup-retain-previous-full-backup-age";
214
215
216
217  /**
218   * The name of the attribute used to specify the number of previous full
219   * backups to retain.
220   */
221  private static final String ATTR_RETAIN_PREVIOUS_FULL_BACKUP_COUNT =
222       "ds-task-backup-retain-previous-full-backup-count";
223
224
225
226  /**
227   * The name of the attribute used to indicate whether to sign the hash of the
228   * backup.
229   */
230  private static final String ATTR_SIGN_HASH = "ds-task-backup-sign-hash";
231
232
233
234  /**
235   * The name of the object class used in backup task entries.
236   */
237  private static final String OC_BACKUP_TASK = "ds-task-backup";
238
239
240
241  /**
242   * The task property that will be used for the backup directory.
243   */
244  private static final TaskProperty PROPERTY_BACKUP_DIRECTORY =
245       new TaskProperty(ATTR_BACKUP_DIRECTORY,
246            INFO_DISPLAY_NAME_BACKUP_DIRECTORY.get(),
247            INFO_DESCRIPTION_BACKUP_DIRECTORY_BACKUP.get(),
248            String.class, true, false, false);
249
250
251
252  /**
253   * The task property that will be used for the backend ID.
254   */
255  private static final TaskProperty PROPERTY_BACKEND_ID =
256       new TaskProperty(ATTR_BACKEND_ID, INFO_DISPLAY_NAME_BACKEND_ID.get(),
257            INFO_DESCRIPTION_BACKEND_ID_BACKUP.get(), String.class, false, true,
258            false);
259
260
261
262  /**
263   * The task property that will be used for the backup ID.
264   */
265  private static final TaskProperty PROPERTY_BACKUP_ID =
266       new TaskProperty(ATTR_BACKUP_ID, INFO_DISPLAY_NAME_BACKUP_ID.get(),
267            INFO_DESCRIPTION_BACKUP_ID_BACKUP.get(), String.class, false, false,
268            true);
269
270
271
272  /**
273   * The task property that will be used for the incremental flag.
274   */
275  private static final TaskProperty PROPERTY_INCREMENTAL =
276       new TaskProperty(ATTR_INCREMENTAL, INFO_DISPLAY_NAME_INCREMENTAL.get(),
277            INFO_DESCRIPTION_INCREMENTAL.get(), Boolean.class, false, false,
278            false);
279
280
281
282  /**
283   * The task property that will be used for the incremental base ID.
284   */
285  private static final TaskProperty PROPERTY_INCREMENTAL_BASE_ID =
286       new TaskProperty(ATTR_INCREMENTAL_BASE_ID,
287            INFO_DISPLAY_NAME_INCREMENTAL_BASE_ID.get(),
288            INFO_DESCRIPTION_INCREMENTAL_BASE_ID.get(), String.class, false,
289            false, true);
290
291
292
293  /**
294   * The task property that will be used for the compress flag.
295   */
296  private static final TaskProperty PROPERTY_COMPRESS =
297       new TaskProperty(ATTR_COMPRESS, INFO_DISPLAY_NAME_COMPRESS.get(),
298            INFO_DESCRIPTION_COMPRESS_BACKUP.get(), Boolean.class, false, false,
299            false);
300
301
302
303  /**
304   * The task property that will be used for the encrypt flag.
305   */
306  private static final TaskProperty PROPERTY_ENCRYPT =
307       new TaskProperty(ATTR_ENCRYPT, INFO_DISPLAY_NAME_ENCRYPT.get(),
308            INFO_DESCRIPTION_ENCRYPT_BACKUP.get(), Boolean.class, false, false,
309            false);
310
311
312
313  /**
314   * The task property that will be used for the encryption passphrase file.
315   */
316  private static final TaskProperty PROPERTY_ENCRYPTION_PASSPHRASE_FILE =
317       new TaskProperty(ATTR_ENCRYPTION_PASSPHRASE_FILE,
318            INFO_DISPLAY_NAME_ENCRYPTION_PASSPHRASE_FILE.get(),
319            INFO_DESCRIPTION_ENCRYPTION_PASSPHRASE_FILE.get(),
320            String.class, false, false, true);
321
322
323
324  /**
325   * The task property that will be used for the encryption settings definition
326   * ID.
327   */
328  private static final TaskProperty PROPERTY_ENCRYPTION_SETTINGS_DEFINITION_ID =
329       new TaskProperty(ATTR_ENCRYPTION_SETTINGS_DEFINITION_ID,
330            INFO_DISPLAY_NAME_ENCRYPTION_SETTINGS_DEFINITION_ID.get(),
331            INFO_DESCRIPTION_ENCRYPTION_SETTINGS_DEFINITION_ID.get(),
332            String.class, false, false, true);
333
334
335
336  /**
337   * The task property that will be used for the hash flag.
338   */
339  private static final TaskProperty PROPERTY_HASH =
340       new TaskProperty(ATTR_HASH, INFO_DISPLAY_NAME_HASH.get(),
341            INFO_DESCRIPTION_HASH_BACKUP.get(), Boolean.class, false, false,
342            false);
343
344
345
346  /**
347   * The task property that will be used for the sign hash flag.
348   */
349  private static final TaskProperty PROPERTY_SIGN_HASH =
350       new TaskProperty(ATTR_SIGN_HASH, INFO_DISPLAY_NAME_SIGN_HASH.get(),
351            INFO_DESCRIPTION_SIGN_HASH_BACKUP.get(), Boolean.class, false,
352            false, false);
353
354
355
356  /**
357   * The task property that will be used for the maximum write rate in megabytes
358   * per second.
359   */
360  private static final TaskProperty PROPERTY_MAX_MEGABYTES_PER_SECOND =
361       new TaskProperty(ATTR_MAX_MEGABYTES_PER_SECOND,
362            INFO_DISPLAY_NAME_BACKUP_MAX_MEGABYTES_PER_SECOND.get(),
363            INFO_DESCRIPTION_BACKUP_MAX_MEGABYTES_PER_SECOND.get(),
364            Long.class, false, false, true);
365
366
367
368  /**
369   * The task property that will be used for the retain previous full backup
370   * age.
371   */
372  private static final TaskProperty PROPERTY_RETAIN_PREVIOUS_FULL_BACKUP_AGE =
373       new TaskProperty(ATTR_RETAIN_PREVIOUS_FULL_BACKUP_AGE,
374            INFO_DISPLAY_NAME_BACKUP_RETAIN_AGE.get(),
375            INFO_DESCRIPTION_BACKUP_RETAIN_AGE.get(),
376            String.class, false, false, true);
377
378
379
380  /**
381   * The task property that will be used for the retain previous full backup
382   * count.
383   */
384  private static final TaskProperty PROPERTY_RETAIN_PREVIOUS_FULL_BACKUP_COUNT =
385       new TaskProperty(ATTR_RETAIN_PREVIOUS_FULL_BACKUP_COUNT,
386            INFO_DISPLAY_NAME_BACKUP_RETAIN_COUNT.get(),
387            INFO_DESCRIPTION_BACKUP_RETAIN_COUNT.get(),
388            Long.class, false, false, true);
389
390
391
392  /**
393   * The serial version UID for this serializable class.
394   */
395  private static final long serialVersionUID = 2637190942057174423L;
396
397
398
399  // Indicates whether to compress the backup.
400  private final boolean compress;
401
402  // Indicates whether to encrypt the backup.
403  private final boolean encrypt;
404
405  // Indicates whether to generate a hash of the backup.
406  private final boolean hash;
407
408  // Indicates whether to sign the backup hash.
409  private final boolean signHash;
410
411  // Indicates whether to perform an incremental backup.
412  private final boolean incremental;
413
414  // The maximum backup write rate in megabytes per second.
415  private final Integer maxMegabytesPerSecond;
416
417  // The retain previous full backup count.
418  private final Integer retainPreviousFullBackupCount;
419
420  // The backend IDs of the backends to back up.
421  private final List<String> backendIDs;
422
423  // The path to the directory in which to write the backup.
424  private final String backupDirectory;
425
426  // The backup ID to use for the backup.
427  private final String backupID;
428
429  // The path to a file containing the passphrase to use to generate the
430  // encryption key.
431  private final String encryptionPassphraseFile;
432
433  // The identifier for the encryption settings definition to use to generate
434  // the encryption key.
435  private final String encryptionSettingsDefinitionID;
436
437  // The backup ID of the backup to use as the base for the incremental backup.
438  private final String incrementalBaseID;
439
440  // The retain previous full backup age.
441  private final String retainPreviousFullBackupAge;
442
443
444
445  /**
446   * Creates a new uninitialized backup task instance which should only be
447   * used for obtaining general information about this task, including the task
448   * name, description, and supported properties.  Attempts to use a task
449   * created with this constructor for any other reason will likely fail.
450   */
451  public BackupTask()
452  {
453    compress = false;
454    encrypt = false;
455    hash = false;
456    signHash = false;
457    incremental = false;
458    maxMegabytesPerSecond = null;
459    retainPreviousFullBackupCount = null;
460    backendIDs = null;
461    backupDirectory = null;
462    backupID = null;
463    encryptionPassphraseFile = null;
464    encryptionSettingsDefinitionID = null;
465    incrementalBaseID = null;
466    retainPreviousFullBackupAge = null;
467  }
468
469
470
471
472  /**
473   * Creates a new backup task with the provided information.
474   *
475   * @param  taskID           The task ID to use for this task.  If it is
476   *                          {@code null} then a UUID will be generated for use
477   *                          as the task ID.
478   * @param  backupDirectory  The path to the directory on the server into which
479   *                          the backup should be written.  If a single backend
480   *                          is to be archived, then this should be the path to
481   *                          the specific backup directory for that backend.
482   *                          If multiple backends are to be archived, then this
483   *                          should be the parent of the directories for each
484   *                          of the backends.  It must not be {@code null}.
485   * @param  backendID        The backend ID of the backend to back up.  It may
486   *                          be {@code null} if all supported backends should
487   *                          be backed up.
488   */
489  public BackupTask(final String taskID, final String backupDirectory,
490                    final String backendID)
491  {
492    this(taskID, backupDirectory,
493         ((backendID == null) ? null : Arrays.asList(backendID)),
494         null, false, null, false, false, false, false, null, null, null, null,
495         null);
496  }
497
498
499
500  /**
501   * Creates a new restore task with the provided information.
502   *
503   * @param  taskID                  The task ID to use for this task.  If it is
504   *                                 {@code null} then a UUID will be generated
505   *                                 for use as the task ID.
506   * @param  backupDirectory         The path to the directory on the server
507   *                                 into which the backup should be written.
508   *                                 If a single backend is to be archived, then
509   *                                 this should be the path to the specific
510   *                                 backup directory for that backend.  If
511   *                                 multiple backends are to be archived, then
512   *                                 this should be the parent of the
513   *                                 directories for each of the backends.  It
514   *                                 must not be {@code null}.
515   * @param  backendIDs              A list of the backend IDs of the backends
516   *                                 to archive.  It may be {@code null} or
517   *                                 empty if all supported backends should be
518   *                                 archived.
519   * @param  backupID                The backup ID to use for this backup.  It
520   *                                 may be {@code null} to indicate that the
521   *                                 server should generate the backup ID.
522   * @param  incremental             Indicates whether to perform an incremental
523   *                                 backup rather than a full backup.
524   * @param  incrementalBaseID       The backup ID of the existing backup on
525   *                                 which to base the incremental backup.  It
526   *                                 may be {@code null} if this is not an
527   *                                 incremental backup or if it should be based
528   *                                 on the most recent backup.
529   * @param  compress                Indicates whether the backup should be
530   *                                 compressed.
531   * @param  encrypt                 Indicates whether the backup should be
532   *                                 encrypted.
533   * @param  hash                    Indicates whether to generate a hash of the
534   *                                 backup contents.
535   * @param  signHash                Indicates whether to sign the hash of the
536   *                                 backup contents.
537   * @param  scheduledStartTime      The time that this task should start
538   *                                 running.
539   * @param  dependencyIDs           The list of task IDs that will be required
540   *                                 to complete before this task will be
541   *                                 eligible to start.
542   * @param  failedDependencyAction  Indicates what action should be taken if
543   *                                 any of the dependencies for this task do
544   *                                 not complete successfully.
545   * @param  notifyOnCompletion      The list of e-mail addresses of individuals
546   *                                 that should be notified when this task
547   *                                 completes.
548   * @param  notifyOnError           The list of e-mail addresses of individuals
549   *                                 that should be notified if this task does
550   *                                 not complete successfully.
551   */
552  public BackupTask(final String taskID, final String backupDirectory,
553                    final List<String> backendIDs, final String backupID,
554                    final boolean incremental, final String incrementalBaseID,
555                    final boolean compress, final boolean encrypt,
556                    final boolean hash, final boolean signHash,
557                    final Date scheduledStartTime,
558                    final List<String> dependencyIDs,
559                    final FailedDependencyAction failedDependencyAction,
560                    final List<String> notifyOnCompletion,
561                    final List<String> notifyOnError)
562  {
563    this(taskID, backupDirectory, backendIDs, backupID, incremental,
564         incrementalBaseID, compress, encrypt, null, null, hash, signHash,
565         null, null, null, scheduledStartTime, dependencyIDs,
566         failedDependencyAction, notifyOnCompletion, notifyOnError);
567  }
568
569
570
571  /**
572   * Creates a new restore task with the provided information.
573   *
574   * @param  taskID                          The task ID to use for this task.
575   *                                         If it is {@code null} then a UUID
576   *                                         will be generated for use as the
577   *                                         task ID.
578   * @param  backupDirectory                 The path to the directory on the
579   *                                         server into which the backup should
580   *                                         be written.  If a single backend is
581   *                                         to be archived, then this should be
582   *                                         the path to the specific backup
583   *                                         directory for that backend.  If
584   *                                         multiple backends are to be
585   *                                         archived, then this should be the
586   *                                         parent of the directories for each
587   *                                         of the backends.  It must not be
588   *                                         {@code null}.
589   * @param  backendIDs                      A list of the backend IDs of the
590   *                                         backends to archive.  It may be
591   *                                         {@code null} or empty if all
592   *                                         supported backends should be
593   *                                         archived.
594   * @param  backupID                        The backup ID to use for this
595   *                                         backup.  It may be {@code null} to
596   *                                         indicate that the server should
597   *                                         generate the backup ID.
598   * @param  incremental                     Indicates whether to perform an
599   *                                         incremental backup rather than a
600   *                                         full backup.
601   * @param  incrementalBaseID               The backup ID of the existing
602   *                                         backup on which to base the
603   *                                         incremental backup.  It may be
604   *                                         {@code null} if this is not an
605   *                                         incremental backup or if it should
606   *                                         be based on the most recent backup.
607   * @param  compress                        Indicates whether the backup should
608   *                                         be compressed.
609   * @param  encrypt                         Indicates whether the backup should
610   *                                         be encrypted.
611   * @param  encryptionPassphraseFile        The path to a file containing the
612   *                                         passphrase to use to generate the
613   *                                         encryption key.  It amy be
614   *                                         {@code null} if the backup is not
615   *                                         to be encrypted, or if the key
616   *                                         should be obtained in some other
617   *                                         way.
618   * @param  encryptionSettingsDefinitionID  The ID of the encryption settings
619   *                                         definition use to generate the
620   *                                         encryption key.  It may be
621   *                                         {@code null} if the backup is not
622   *                                         to be encrypted, or if the key
623   *                                         should be obtained in some other
624   *                                         way.
625   * @param  hash                            Indicates whether to generate a
626   *                                         hash of the backup contents.
627   * @param  signHash                        Indicates whether to sign the hash
628   *                                         of the backup contents.
629   * @param  maxMegabytesPerSecond           The maximum rate in megabytes per
630   *                                         second at which the backup should
631   *                                         be written.
632   * @param  retainPreviousFullBackupCount   The minimum number of previous
633   *                                         backups to retain.
634   * @param  retainPreviousFullBackupAge     A string representation of the
635   *                                         minimum age of previous backups to
636   *                                         retain.  The age should be
637   *                                         formatted in the same way as values
638   *                                         for the {@link DurationArgument}
639   *                                         class.
640   * @param  scheduledStartTime              The time that this task should
641   *                                         start running.
642   * @param  dependencyIDs                   The list of task IDs that will be
643   *                                         required to complete before this
644   *                                         task will be eligible to start.
645   * @param  failedDependencyAction          Indicates what action should be
646   *                                         taken if any of the dependencies
647   *                                         for this task do not complete
648   *                                         successfully.
649   * @param  notifyOnCompletion              The list of e-mail addresses of
650   *                                         individuals that should be notified
651   *                                         when this task completes.
652   * @param  notifyOnError                   The list of e-mail addresses of
653   *                                         individuals that should be notified
654   *                                         if this task does not complete
655   *                                         successfully.
656   */
657  public BackupTask(final String taskID, final String backupDirectory,
658                    final List<String> backendIDs, final String backupID,
659                    final boolean incremental, final String incrementalBaseID,
660                    final boolean compress, final boolean encrypt,
661                    final String encryptionPassphraseFile,
662                    final String encryptionSettingsDefinitionID,
663                    final boolean hash, final boolean signHash,
664                    final Integer maxMegabytesPerSecond,
665                    final Integer retainPreviousFullBackupCount,
666                    final String retainPreviousFullBackupAge,
667                    final Date scheduledStartTime,
668                    final List<String> dependencyIDs,
669                    final FailedDependencyAction failedDependencyAction,
670                    final List<String> notifyOnCompletion,
671                    final List<String> notifyOnError)
672  {
673    super(taskID, BACKUP_TASK_CLASS, scheduledStartTime,
674          dependencyIDs, failedDependencyAction, notifyOnCompletion,
675          notifyOnError);
676
677    ensureNotNull(backupDirectory);
678
679    this.backupDirectory = backupDirectory;
680    this.backupID = backupID;
681    this.incremental = incremental;
682    this.incrementalBaseID = incrementalBaseID;
683    this.compress = compress;
684    this.encrypt = encrypt;
685    this.encryptionPassphraseFile = encryptionPassphraseFile;
686    this.encryptionSettingsDefinitionID = encryptionSettingsDefinitionID;
687    this.hash = hash;
688    this.signHash = signHash;
689    this.maxMegabytesPerSecond = maxMegabytesPerSecond;
690    this.retainPreviousFullBackupCount = retainPreviousFullBackupCount;
691    this.retainPreviousFullBackupAge = retainPreviousFullBackupAge;
692
693    if (backendIDs == null)
694    {
695      this.backendIDs = Collections.emptyList();
696    }
697    else
698    {
699      this.backendIDs = Collections.unmodifiableList(backendIDs);
700    }
701  }
702
703
704
705  /**
706   * Creates a new backup task from the provided entry.
707   *
708   * @param  entry  The entry to use to create this backup task.
709   *
710   * @throws  TaskException  If the provided entry cannot be parsed as a backup
711   *                         task entry.
712   */
713  public BackupTask(final Entry entry)
714         throws TaskException
715  {
716    super(entry);
717
718
719    // Get the backup directory.  It must be present.
720    backupDirectory = entry.getAttributeValue(ATTR_BACKUP_DIRECTORY);
721    if (backupDirectory == null)
722    {
723      throw new TaskException(ERR_BACKUP_NO_BACKUP_DIRECTORY.get(
724                                   getTaskEntryDN()));
725    }
726
727
728    // Get the set of backend IDs.  It may be absent.
729    backendIDs = parseStringList(entry, ATTR_BACKEND_ID);
730
731
732    // Get the backup ID.  It may be absent.
733    backupID = entry.getAttributeValue(ATTR_BACKUP_ID);
734
735
736    // Get the incremental flag.  It may be absent.
737    incremental = parseBooleanValue(entry, ATTR_INCREMENTAL, false);
738
739
740    // Get the incremental base ID.  It may be absent.
741    incrementalBaseID = entry.getAttributeValue(ATTR_INCREMENTAL_BASE_ID);
742
743
744    // Determine whether to compress the backup.  It may be absent.
745    compress = parseBooleanValue(entry, ATTR_COMPRESS, false);
746
747
748    // Determine whether to encrypt the backup.  It may be absent.
749    encrypt = parseBooleanValue(entry, ATTR_ENCRYPT, false);
750
751
752    // Get the path to the encryption passphrase file.  It may be absent.
753    encryptionPassphraseFile =
754         entry.getAttributeValue(ATTR_ENCRYPTION_PASSPHRASE_FILE);
755
756
757    // Get the encryption settings definition ID.  It may be absent.
758    encryptionSettingsDefinitionID =
759         entry.getAttributeValue(ATTR_ENCRYPTION_SETTINGS_DEFINITION_ID);
760
761
762    // Determine whether to hash the backup.  It may be absent.
763    hash = parseBooleanValue(entry, ATTR_HASH, false);
764
765
766    // Determine whether to sign the hash.  It may be absent.
767    signHash = parseBooleanValue(entry, ATTR_SIGN_HASH, false);
768
769
770    // Get the maximum write rate in megabytes per second.  It may be absent.
771    maxMegabytesPerSecond =
772         entry.getAttributeValueAsInteger(ATTR_MAX_MEGABYTES_PER_SECOND);
773
774
775    // Get the retain previous full backup count.  It may be absent.
776    retainPreviousFullBackupCount = entry.getAttributeValueAsInteger(
777         ATTR_RETAIN_PREVIOUS_FULL_BACKUP_COUNT);
778
779
780    // Get the retain previous full backup age.  It may be absent.
781    retainPreviousFullBackupAge = entry.getAttributeValue(
782         ATTR_RETAIN_PREVIOUS_FULL_BACKUP_AGE);
783  }
784
785
786
787  /**
788   * Creates a new backup task from the provided set of task properties.
789   *
790   * @param  properties  The set of task properties and their corresponding
791   *                     values to use for the task.  It must not be
792   *                     {@code null}.
793   *
794   * @throws  TaskException  If the provided set of properties cannot be used to
795   *                         create a valid backup task.
796   */
797  public BackupTask(final Map<TaskProperty,List<Object>> properties)
798         throws TaskException
799  {
800    super(BACKUP_TASK_CLASS, properties);
801
802    boolean  c           = false;
803    boolean  e           = false;
804    boolean  h           = false;
805    boolean  i           = false;
806    boolean  s           = false;
807    Integer  maxMB       = null;
808    Integer  retainCount = null;
809    String   bDir        = null;
810    String   bkID        = null;
811    String   incID       = null;
812    String   encID       = null;
813    String   encPWFile   = null;
814    String   retainAge   = null;
815    String[] beIDs       = StaticUtils.NO_STRINGS;
816
817    for (final Map.Entry<TaskProperty,List<Object>> entry :
818         properties.entrySet())
819    {
820      final TaskProperty p = entry.getKey();
821      final String attrName = p.getAttributeName();
822      final List<Object> values = entry.getValue();
823
824      if (attrName.equalsIgnoreCase(ATTR_BACKUP_DIRECTORY))
825      {
826        bDir = parseString(p, values, bDir);
827      }
828      else if (attrName.equalsIgnoreCase(ATTR_BACKEND_ID))
829      {
830        beIDs = parseStrings(p, values, beIDs);
831      }
832      else if (attrName.equalsIgnoreCase(ATTR_BACKUP_ID))
833      {
834        bkID = parseString(p, values, bkID);
835      }
836      else if (attrName.equalsIgnoreCase(ATTR_INCREMENTAL))
837      {
838        i = parseBoolean(p, values, i);
839      }
840      else if (attrName.equalsIgnoreCase(ATTR_INCREMENTAL_BASE_ID))
841      {
842        incID = parseString(p, values, incID);
843      }
844      else if (attrName.equalsIgnoreCase(ATTR_COMPRESS))
845      {
846        c = parseBoolean(p, values, c);
847      }
848      else if (attrName.equalsIgnoreCase(ATTR_ENCRYPT))
849      {
850        e = parseBoolean(p, values, e);
851      }
852      else if (attrName.equalsIgnoreCase(ATTR_ENCRYPTION_PASSPHRASE_FILE))
853      {
854        encPWFile = parseString(p, values, encPWFile);
855      }
856      else if (attrName.equalsIgnoreCase(
857           ATTR_ENCRYPTION_SETTINGS_DEFINITION_ID))
858      {
859        encID = parseString(p, values, encID);
860      }
861      else if (attrName.equalsIgnoreCase(ATTR_HASH))
862      {
863        h = parseBoolean(p, values, h);
864      }
865      else if (attrName.equalsIgnoreCase(ATTR_SIGN_HASH))
866      {
867        s = parseBoolean(p, values, s);
868      }
869      else if (attrName.equalsIgnoreCase(ATTR_MAX_MEGABYTES_PER_SECOND))
870      {
871        final Long maxMBLong = parseLong(p, values, null);
872        if (maxMBLong == null)
873        {
874          maxMB = null;
875        }
876        else
877        {
878          maxMB = maxMBLong.intValue();
879        }
880      }
881      else if (attrName.equalsIgnoreCase(
882           ATTR_RETAIN_PREVIOUS_FULL_BACKUP_COUNT))
883      {
884        final Long retainCountLong = parseLong(p, values, null);
885        if (retainCountLong == null)
886        {
887          retainCount = null;
888        }
889        else
890        {
891          retainCount = retainCountLong.intValue();
892        }
893      }
894      else if (attrName.equalsIgnoreCase(ATTR_RETAIN_PREVIOUS_FULL_BACKUP_AGE))
895      {
896        retainAge = parseString(p, values, retainAge);
897      }
898    }
899
900    if (bDir == null)
901    {
902      throw new TaskException(ERR_BACKUP_NO_BACKUP_DIRECTORY.get(
903                                   getTaskEntryDN()));
904    }
905
906    backupDirectory = bDir;
907    backendIDs = Arrays.asList(beIDs);
908    backupID = bkID;
909    incremental = i;
910    incrementalBaseID = incID;
911    compress = c;
912    encrypt = e;
913    encryptionPassphraseFile = encPWFile;
914    encryptionSettingsDefinitionID = encID;
915    hash = h;
916    signHash = s;
917    maxMegabytesPerSecond = maxMB;
918    retainPreviousFullBackupCount = retainCount;
919    retainPreviousFullBackupAge = retainAge;
920  }
921
922
923
924  /**
925   * {@inheritDoc}
926   */
927  @Override()
928  public String getTaskName()
929  {
930    return INFO_TASK_NAME_BACKUP.get();
931  }
932
933
934
935  /**
936   * {@inheritDoc}
937   */
938  @Override()
939  public String getTaskDescription()
940  {
941    return INFO_TASK_DESCRIPTION_BACKUP.get();
942  }
943
944
945
946  /**
947   * Retrieves the path to the backup directory in which the backup files should
948   * be written.  If a single backend is to be archived, then this will be the
949   * directory in which the backup files are written.  If multiple backends are
950   * to be archived, then this will be the parent of the directories containing
951   * the backups for each backend.
952   *
953   * @return  The path to the backup directory in which the backup files should
954   *          be written.
955   */
956  public String getBackupDirectory()
957  {
958    return backupDirectory;
959  }
960
961
962
963  /**
964   * Indicates whether the server should back up all supported backends.
965   *
966   * @return  {@code true} if the server should back up all supported backends,
967   *          or {@code false} if it should back up a specified backend or set
968   *          of backends.
969   */
970  public boolean backupAll()
971  {
972    return backendIDs.isEmpty();
973  }
974
975
976
977  /**
978   * Retrieves the set of backend IDs for the backends that should be archived.
979   *
980   * @return  The set of backend IDs for the backends that should be archived,
981   *          or an empty list if the server should back up all supported
982   *          backends.
983   */
984  public List<String> getBackendIDs()
985  {
986    return backendIDs;
987  }
988
989
990
991  /**
992   * Retrieves the backup ID for the backup to generate.
993   *
994   * @return  The backup ID for the backup to generate, or {@code null} if the
995   *          server should generate a backup ID.
996   */
997  public String getBackupID()
998  {
999    return backupID;
1000  }
1001
1002
1003
1004  /**
1005   * Indicates whether the server should attempt to perform an incremental
1006   * backup rather than a full backup.
1007   *
1008   * @return  {@code true} if the server should attempt to perform an
1009   *          incremental backup, or {@code false} for a full backup.
1010   */
1011  public boolean incremental()
1012  {
1013    return incremental;
1014  }
1015
1016
1017
1018  /**
1019   * Retrieves the backup ID of the existing backup on which the incremental
1020   * backup should be based.
1021   *
1022   * @return  The backup ID of the existing backup on which the incremental
1023   *          backup should be based, or {@code null} if it is not an
1024   *          incremental backup or the server should use the most recent
1025   *          backup available as the base for the new incremental backup.
1026   */
1027  public String getIncrementalBaseID()
1028  {
1029    return incrementalBaseID;
1030  }
1031
1032
1033
1034  /**
1035   * Indicates whether the backup should be compressed.
1036   *
1037   * @return  {@code true} if the backup should be compressed, or {@code false}
1038   *          if not.
1039   */
1040  public boolean compress()
1041  {
1042    return compress;
1043  }
1044
1045
1046
1047  /**
1048   * Indicates whether the backup should be encrypted.
1049   *
1050   * @return  {@code true} if the backup should be encrypted, or {@code false}
1051   *          if not.
1052   */
1053  public boolean encrypt()
1054  {
1055    return encrypt;
1056  }
1057
1058
1059
1060  /**
1061   * Retrieves the path to a file that contains the passphrase to use to
1062   * generate the encryption key.
1063   *
1064   * @return  The path to a file that contains the passphrase to use to
1065   *          generate the encryption key, or {@code null} if the backup should
1066   *          not be encrypted or if the encryption key should be obtained
1067   *          through some other means.
1068   */
1069  public String getEncryptionPassphraseFile()
1070  {
1071    return encryptionPassphraseFile;
1072  }
1073
1074
1075
1076  /**
1077   * Retrieves the identifier of the encryption settings definition to use to
1078   * generate the encryption key.
1079   *
1080   * @return  The identifier of the encryption settings definition to use to
1081   *          generate the encryption key, or {@code null} if the backup should
1082   *          not be encrypted or if the encryption key should be obtained
1083   *          through some other means.
1084   */
1085  public String getEncryptionSettingsDefinitionID()
1086  {
1087    return encryptionSettingsDefinitionID;
1088  }
1089
1090
1091
1092  /**
1093   * Indicates whether the server should generate a hash of the backup.
1094   *
1095   * @return  {@code true} if the server should generate a hash of the backup,
1096   *          or {@code false} if not.
1097   */
1098  public boolean hash()
1099  {
1100    return hash;
1101  }
1102
1103
1104
1105  /**
1106   * Indicates whether the server should sign the backup hash.
1107   *
1108   * @return  {@code true} if the server should sign the backup hash, or
1109   *          {@code false} if not.
1110   */
1111  public boolean signHash()
1112  {
1113    return signHash;
1114  }
1115
1116
1117
1118  /**
1119   * Retrieves the maximum rate, in megabytes per second, at which the backup
1120   * should be written.
1121   *
1122   * @return  The maximum rate, in megabytes per second, at which the backup
1123   *          should be written, or {@code null} if the writing should not be
1124   *          rate limited.
1125   */
1126  public Integer getMaxMegabytesPerSecond()
1127  {
1128    return maxMegabytesPerSecond;
1129  }
1130
1131
1132
1133  /**
1134   * Retrieves the minimum number of previous full backups that should be
1135   * retained if the new backup is created successfully.
1136   *
1137   * @return  The minimum number of previous full backups that should be
1138   *          retained if the new backup is created successfully, or
1139   *          {@code null} if no backups should be removed or if the backup age
1140   *          should be the only retention criteria.
1141   */
1142  public Integer getRetainPreviousFullBackupCount()
1143  {
1144    return retainPreviousFullBackupCount;
1145  }
1146
1147
1148
1149  /**
1150   * Retrieves a string representation of the minimum age of previous full
1151   * backups that should be retained if the new backup is created successfully.
1152   *
1153   * @return  A string representation fo the minimum age of previous full
1154   *          backups that should be retained if the new backup is created
1155   *          successfully, or {@code null} if no backups should be removed or
1156   *          if the backup count should be the only retention criteria.
1157   */
1158  public String getRetainPreviousFullBackupAge()
1159  {
1160    return retainPreviousFullBackupAge;
1161  }
1162
1163
1164
1165  /**
1166   * {@inheritDoc}
1167   */
1168  @Override()
1169  protected List<String> getAdditionalObjectClasses()
1170  {
1171    return Arrays.asList(OC_BACKUP_TASK);
1172  }
1173
1174
1175
1176  /**
1177   * {@inheritDoc}
1178   */
1179  @Override()
1180  protected List<Attribute> getAdditionalAttributes()
1181  {
1182    final ArrayList<Attribute> attrs = new ArrayList<Attribute>(20);
1183
1184    attrs.add(new Attribute(ATTR_BACKUP_DIRECTORY, backupDirectory));
1185    attrs.add(new Attribute(ATTR_INCREMENTAL,  String.valueOf(incremental)));
1186    attrs.add(new Attribute(ATTR_COMPRESS, String.valueOf(compress)));
1187    attrs.add(new Attribute(ATTR_ENCRYPT, String.valueOf(encrypt)));
1188    attrs.add(new Attribute(ATTR_HASH, String.valueOf(hash)));
1189    attrs.add(new Attribute(ATTR_SIGN_HASH, String.valueOf(signHash)));
1190
1191    if (backendIDs.isEmpty())
1192    {
1193      attrs.add(new Attribute(ATTR_BACKUP_ALL, "true"));
1194    }
1195    else
1196    {
1197      attrs.add(new Attribute(ATTR_BACKEND_ID, backendIDs));
1198    }
1199
1200    if (backupID != null)
1201    {
1202      attrs.add(new Attribute(ATTR_BACKUP_ID, backupID));
1203    }
1204
1205    if (incrementalBaseID != null)
1206    {
1207      attrs.add(new Attribute(ATTR_INCREMENTAL_BASE_ID, incrementalBaseID));
1208    }
1209
1210    if (encryptionPassphraseFile != null)
1211    {
1212      attrs.add(new Attribute(ATTR_ENCRYPTION_PASSPHRASE_FILE,
1213           encryptionPassphraseFile));
1214    }
1215
1216    if (encryptionSettingsDefinitionID != null)
1217    {
1218      attrs.add(new Attribute(ATTR_ENCRYPTION_SETTINGS_DEFINITION_ID,
1219           encryptionSettingsDefinitionID));
1220    }
1221
1222    if (maxMegabytesPerSecond != null)
1223    {
1224      attrs.add(new Attribute(ATTR_MAX_MEGABYTES_PER_SECOND,
1225           String.valueOf(maxMegabytesPerSecond)));
1226    }
1227
1228    if (retainPreviousFullBackupCount != null)
1229    {
1230      attrs.add(new Attribute(ATTR_RETAIN_PREVIOUS_FULL_BACKUP_COUNT,
1231           String.valueOf(retainPreviousFullBackupCount)));
1232    }
1233
1234    if (retainPreviousFullBackupAge != null)
1235    {
1236      attrs.add(new Attribute(ATTR_RETAIN_PREVIOUS_FULL_BACKUP_AGE,
1237           retainPreviousFullBackupAge));
1238    }
1239
1240    return attrs;
1241  }
1242
1243
1244
1245  /**
1246   * {@inheritDoc}
1247   */
1248  @Override()
1249  public List<TaskProperty> getTaskSpecificProperties()
1250  {
1251    final List<TaskProperty> propList = Arrays.asList(
1252         PROPERTY_BACKUP_DIRECTORY,
1253         PROPERTY_BACKEND_ID,
1254         PROPERTY_BACKUP_ID,
1255         PROPERTY_INCREMENTAL,
1256         PROPERTY_INCREMENTAL_BASE_ID,
1257         PROPERTY_COMPRESS,
1258         PROPERTY_ENCRYPT,
1259         PROPERTY_ENCRYPTION_PASSPHRASE_FILE,
1260         PROPERTY_ENCRYPTION_SETTINGS_DEFINITION_ID,
1261         PROPERTY_HASH,
1262         PROPERTY_SIGN_HASH,
1263         PROPERTY_MAX_MEGABYTES_PER_SECOND,
1264         PROPERTY_RETAIN_PREVIOUS_FULL_BACKUP_COUNT,
1265         PROPERTY_RETAIN_PREVIOUS_FULL_BACKUP_AGE);
1266
1267    return Collections.unmodifiableList(propList);
1268  }
1269
1270
1271
1272  /**
1273   * {@inheritDoc}
1274   */
1275  @Override()
1276  public Map<TaskProperty,List<Object>> getTaskPropertyValues()
1277  {
1278    final LinkedHashMap<TaskProperty,List<Object>> props =
1279         new LinkedHashMap<TaskProperty,List<Object>>();
1280
1281    props.put(PROPERTY_BACKUP_DIRECTORY,
1282         Collections.<Object>unmodifiableList(Arrays.asList(backupDirectory)));
1283
1284    props.put(PROPERTY_BACKEND_ID,
1285              Collections.<Object>unmodifiableList(backendIDs));
1286
1287    if (backupID == null)
1288    {
1289      props.put(PROPERTY_BACKUP_ID, Collections.emptyList());
1290    }
1291    else
1292    {
1293      props.put(PROPERTY_BACKUP_ID,
1294                Collections.<Object>unmodifiableList(Arrays.asList(backupID)));
1295    }
1296
1297    props.put(PROPERTY_INCREMENTAL,
1298              Collections.<Object>unmodifiableList(Arrays.asList(incremental)));
1299
1300    if (incrementalBaseID == null)
1301    {
1302      props.put(PROPERTY_INCREMENTAL_BASE_ID, Collections.emptyList());
1303    }
1304    else
1305    {
1306      props.put(PROPERTY_INCREMENTAL_BASE_ID,
1307                Collections.<Object>unmodifiableList(Arrays.asList(
1308                     incrementalBaseID)));
1309    }
1310
1311    props.put(PROPERTY_COMPRESS,
1312              Collections.<Object>unmodifiableList(Arrays.asList(compress)));
1313
1314    props.put(PROPERTY_ENCRYPT,
1315              Collections.<Object>unmodifiableList(Arrays.asList(encrypt)));
1316
1317    if (encryptionPassphraseFile == null)
1318    {
1319      props.put(PROPERTY_ENCRYPTION_PASSPHRASE_FILE, Collections.emptyList());
1320    }
1321    else
1322    {
1323      props.put(PROPERTY_ENCRYPTION_PASSPHRASE_FILE,
1324         Collections.<Object>unmodifiableList(Arrays.asList(
1325              encryptionPassphraseFile)));
1326    }
1327
1328    if (encryptionSettingsDefinitionID == null)
1329    {
1330      props.put(PROPERTY_ENCRYPTION_SETTINGS_DEFINITION_ID,
1331           Collections.emptyList());
1332    }
1333    else
1334    {
1335      props.put(PROPERTY_ENCRYPTION_SETTINGS_DEFINITION_ID,
1336         Collections.<Object>unmodifiableList(Arrays.asList(
1337              encryptionSettingsDefinitionID)));
1338    }
1339
1340    props.put(PROPERTY_HASH,
1341              Collections.<Object>unmodifiableList(Arrays.asList(hash)));
1342
1343    props.put(PROPERTY_SIGN_HASH,
1344              Collections.<Object>unmodifiableList(Arrays.asList(signHash)));
1345
1346    if (maxMegabytesPerSecond == null)
1347    {
1348      props.put(PROPERTY_MAX_MEGABYTES_PER_SECOND, Collections.emptyList());
1349    }
1350    else
1351    {
1352      props.put(PROPERTY_MAX_MEGABYTES_PER_SECOND,
1353         Collections.<Object>unmodifiableList(Arrays.asList(
1354              maxMegabytesPerSecond.longValue())));
1355    }
1356
1357    if (retainPreviousFullBackupCount == null)
1358    {
1359      props.put(PROPERTY_RETAIN_PREVIOUS_FULL_BACKUP_COUNT,
1360           Collections.emptyList());
1361    }
1362    else
1363    {
1364      props.put(PROPERTY_RETAIN_PREVIOUS_FULL_BACKUP_COUNT,
1365         Collections.<Object>unmodifiableList(Arrays.asList(
1366              retainPreviousFullBackupCount.longValue())));
1367    }
1368
1369    if (retainPreviousFullBackupAge == null)
1370    {
1371      props.put(PROPERTY_RETAIN_PREVIOUS_FULL_BACKUP_AGE,
1372           Collections.emptyList());
1373    }
1374    else
1375    {
1376      props.put(PROPERTY_RETAIN_PREVIOUS_FULL_BACKUP_AGE,
1377         Collections.<Object>unmodifiableList(Arrays.asList(
1378              retainPreviousFullBackupAge)));
1379    }
1380
1381    props.putAll(super.getTaskPropertyValues());
1382    return Collections.unmodifiableMap(props);
1383  }
1384}