001/*
002 * Copyright 2008-2017 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2015-2017 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;
039
040import static com.unboundid.ldap.sdk.unboundidds.tasks.TaskMessages.*;
041import static com.unboundid.util.Validator.*;
042
043
044
045/**
046 * This class defines a Directory Server task that can be used to back up one or
047 * more Directory Server backends.
048 * <BR>
049 * <BLOCKQUOTE>
050 *   <B>NOTE:</B>  This class, and other classes within the
051 *   {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
052 *   supported for use against Ping Identity, UnboundID, and Alcatel-Lucent 8661
053 *   server products.  These classes provide support for proprietary
054 *   functionality or for external specifications that are not considered stable
055 *   or mature enough to be guaranteed to work in an interoperable way with
056 *   other types of LDAP servers.
057 * </BLOCKQUOTE>
058 * <BR>
059 * The properties that are available for use with this type of task include:
060 * <UL>
061 *   <LI>The path to the directory in which the backup should be placed.  If
062 *       multiple backends are to be backed up at once, then this should be the
063 *       parent of the backup directories for each backend.  This must be
064 *       provided when scheduling this task.</LI>
065 *   <LI>The backend IDs of the backends to archive.  If this is not provided,
066 *       then the server will attempt to back up all supported backends.</LI>
067 *   <LI>The backup ID to use for the backup.  If this is not provided, then the
068 *       server will generate a backup ID.</LI>
069 *   <LI>A flag that indicates whether the backup should be an incremental
070 *       backup (if the backend supports that capability) or a full backup.</LI>
071 *   <LI>The backup ID of the existing backup on which the incremental backup
072 *       should be based.  If this is not provided and an incremental backup
073 *       is to be performed, then it will be based on the most recent backup in
074 *       the backup directory.</LI>
075 *   <LI>A flag that indicates whether to compress the contents of the
076 *       backup.</LI>
077 *   <LI>A flag that indicates whether to encrypt the contents of the
078 *       backup.</LI>
079 *   <LI>A flag that indicates whether to hash the contents of the backup to use
080 *       as a checksum for verifying the integrity of the backup.</LI>
081 *   <LI>A flag that indicates whether to sign the backup hash in order to
082 *       prevent anyone from tampering with it.</LI>
083 * </UL>
084
085 */
086@NotMutable()
087@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
088public final class BackupTask
089       extends Task
090{
091  /**
092   * The fully-qualified name of the Java class that is used for the backup
093   * task.
094   */
095  static final String BACKUP_TASK_CLASS =
096       "com.unboundid.directory.server.tasks.BackupTask";
097
098
099
100  /**
101   * The name of the attribute used to specify backend IDs of the backends to
102   * archive.
103   */
104  private static final String ATTR_BACKEND_ID = "ds-task-backup-backend-id";
105
106
107
108  /**
109   * The name of the attribute used to indicate whether to back up the contents
110   * of all supported backends.
111   */
112  private static final String ATTR_BACKUP_ALL = "ds-task-backup-all";
113
114
115
116  /**
117   * The name of the attribute used to specify the path to the directory in
118   * which the backup is to be written.
119   */
120  private static final String ATTR_BACKUP_DIRECTORY =
121       "ds-backup-directory-path";
122
123
124
125  /**
126   * The name of the attribute used to specify the backup ID for the backup.
127   */
128  private static final String ATTR_BACKUP_ID = "ds-backup-id";
129
130
131
132  /**
133   * The name of the attribute used to indicate whether to compress the backup.
134   */
135  private static final String ATTR_COMPRESS = "ds-task-backup-compress";
136
137
138
139  /**
140   * The name of the attribute used to indicate whether to encrypt the backup.
141   */
142  private static final String ATTR_ENCRYPT = "ds-task-backup-encrypt";
143
144
145
146  /**
147   * The name of the attribute used to indicate whether to create a hash of the
148   * backup.
149   */
150  private static final String ATTR_HASH = "ds-task-backup-hash";
151
152
153
154  /**
155   * The name of the attribute used to indicate whether to perform an
156   * incremental backup rather than a full backup.
157   */
158  private static final String ATTR_INCREMENTAL = "ds-task-backup-incremental";
159
160
161
162  /**
163   * The name of the attribute used to specify the backup ID of the backup
164   * on which to base the incremental backup.
165   */
166  private static final String ATTR_INCREMENTAL_BASE_ID =
167       "ds-task-backup-incremental-base-id";
168
169
170
171  /**
172   * The name of the attribute used to indicate whether to sign the hash of the
173   * backup.
174   */
175  private static final String ATTR_SIGN_HASH = "ds-task-backup-sign-hash";
176
177
178
179  /**
180   * The name of the object class used in backup task entries.
181   */
182  private static final String OC_BACKUP_TASK = "ds-task-backup";
183
184
185
186  /**
187   * The task property that will be used for the backup directory.
188   */
189  private static final TaskProperty PROPERTY_BACKUP_DIRECTORY =
190       new TaskProperty(ATTR_BACKUP_DIRECTORY,
191                        INFO_DISPLAY_NAME_BACKUP_DIRECTORY.get(),
192                        INFO_DESCRIPTION_BACKUP_DIRECTORY_BACKUP.get(),
193                        String.class, true, false, false);
194
195
196
197  /**
198   * The task property that will be used for the backend ID.
199   */
200  private static final TaskProperty PROPERTY_BACKEND_ID =
201       new TaskProperty(ATTR_BACKEND_ID, INFO_DISPLAY_NAME_BACKEND_ID.get(),
202                        INFO_DESCRIPTION_BACKEND_ID_BACKUP.get(), String.class,
203                        false, true, false);
204
205
206
207  /**
208   * The task property that will be used for the backup ID.
209   */
210  private static final TaskProperty PROPERTY_BACKUP_ID =
211       new TaskProperty(ATTR_BACKUP_ID, INFO_DISPLAY_NAME_BACKUP_ID.get(),
212                        INFO_DESCRIPTION_BACKUP_ID_BACKUP.get(), String.class,
213                        false, false, true);
214
215
216
217  /**
218   * The task property that will be used for the incremental flag.
219   */
220  private static final TaskProperty PROPERTY_INCREMENTAL =
221       new TaskProperty(ATTR_INCREMENTAL, INFO_DISPLAY_NAME_INCREMENTAL.get(),
222                        INFO_DESCRIPTION_INCREMENTAL.get(), Boolean.class,
223                        false, false, false);
224
225
226
227  /**
228   * The task property that will be used for the incremental base ID.
229   */
230  private static final TaskProperty PROPERTY_INCREMENTAL_BASE_ID =
231       new TaskProperty(ATTR_INCREMENTAL_BASE_ID,
232                        INFO_DISPLAY_NAME_INCREMENTAL_BASE_ID.get(),
233                        INFO_DESCRIPTION_INCREMENTAL_BASE_ID.get(),
234                        String.class, false, false, true);
235
236
237
238  /**
239   * The task property that will be used for the compress flag.
240   */
241  private static final TaskProperty PROPERTY_COMPRESS =
242       new TaskProperty(ATTR_COMPRESS, INFO_DISPLAY_NAME_COMPRESS.get(),
243                        INFO_DESCRIPTION_COMPRESS_BACKUP.get(), Boolean.class,
244                        false, false, false);
245
246
247
248  /**
249   * The task property that will be used for the encrypt flag.
250   */
251  private static final TaskProperty PROPERTY_ENCRYPT =
252       new TaskProperty(ATTR_ENCRYPT, INFO_DISPLAY_NAME_ENCRYPT.get(),
253                        INFO_DESCRIPTION_ENCRYPT_BACKUP.get(), Boolean.class,
254                        false, false, false);
255
256
257
258  /**
259   * The task property that will be used for the hash flag.
260   */
261  private static final TaskProperty PROPERTY_HASH =
262       new TaskProperty(ATTR_HASH, INFO_DISPLAY_NAME_HASH.get(),
263                        INFO_DESCRIPTION_HASH_BACKUP.get(), Boolean.class,
264                        false, false, false);
265
266
267
268  /**
269   * The task property that will be used for the sign hash flag.
270   */
271  private static final TaskProperty PROPERTY_SIGN_HASH =
272       new TaskProperty(ATTR_SIGN_HASH, INFO_DISPLAY_NAME_SIGN_HASH.get(),
273                        INFO_DESCRIPTION_SIGN_HASH_BACKUP.get(), Boolean.class,
274                        false, false, false);
275
276
277
278
279  /**
280   * The serial version UID for this serializable class.
281   */
282  private static final long serialVersionUID = 8680226715226034105L;
283
284
285
286  // Indicates whether to compress the backup.
287  private final boolean compress;
288
289  // Indicates whether to encrypt the backup.
290  private final boolean encrypt;
291
292  // Indicates whether to generate a hash of the backup.
293  private final boolean hash;
294
295  // Indicates whether to sign the backup hash.
296  private final boolean signHash;
297
298  // Indicates whether to perform an incremental backup.
299  private final boolean incremental;
300
301  // The backend IDs of the backends to back up.
302  private final List<String> backendIDs;
303
304  // The path to the directory in which to write the backup.
305  private final String backupDirectory;
306
307  // The backup ID to use for the backup.
308  private final String backupID;
309
310  // The backup ID of the backup to use as the base for the incremental backup.
311  private final String incrementalBaseID;
312
313
314
315  /**
316   * Creates a new uninitialized backup task instance which should only be
317   * used for obtaining general information about this task, including the task
318   * name, description, and supported properties.  Attempts to use a task
319   * created with this constructor for any other reason will likely fail.
320   */
321  public BackupTask()
322  {
323    compress          = false;
324    encrypt           = false;
325    hash              = false;
326    signHash          = false;
327    incremental       = false;
328    backendIDs        = null;
329    backupDirectory   = null;
330    backupID          = null;
331    incrementalBaseID = null;
332  }
333
334
335
336
337  /**
338   * Creates a new backup task with the provided information.
339   *
340   * @param  taskID           The task ID to use for this task.  If it is
341   *                          {@code null} then a UUID will be generated for use
342   *                          as the task ID.
343   * @param  backupDirectory  The path to the directory on the server into which
344   *                          the backup should be written.  If a single backend
345   *                          is to be archived, then this should be the path to
346   *                          the specific backup directory for that backend.
347   *                          If multiple backends are to be archived, then this
348   *                          should be the parent of the directories for each
349   *                          of the backends.  It must not be {@code null}.
350   * @param  backendID        The backend ID of the backend to back up.  It may
351   *                          be {@code null} if all supported backends should
352   *                          be backed up.
353   */
354  public BackupTask(final String taskID, final String backupDirectory,
355                    final String backendID)
356  {
357    this(taskID, backupDirectory,
358         ((backendID == null) ? null : Arrays.asList(backendID)),
359         null, false, null, false, false, false, false, null, null, null, null,
360         null);
361  }
362
363
364
365  /**
366   * Creates a new restore task with the provided information.
367   *
368   * @param  taskID                  The task ID to use for this task.  If it is
369   *                                 {@code null} then a UUID will be generated
370   *                                 for use as the task ID.
371   * @param  backupDirectory         The path to the directory on the server
372   *                                 into which the backup should be written.
373   *                                 If a single backend is to be archived, then
374   *                                 this should be the path to the specific
375   *                                 backup directory for that backend.  If
376   *                                 multiple backends are to be archived, then
377   *                                 this should be the parent of the
378   *                                 directories for each of the backends.  It
379   *                                 must not be {@code null}.
380   * @param  backendIDs              A list of the backend IDs of the backends
381   *                                 to archive.  It may be {@code null} or
382   *                                 empty if all supported backends should be
383   *                                 archived.
384   * @param  backupID                The backup ID to use for this backup.  It
385   *                                 may be {@code null} to indicate that the
386   *                                 server should generate the backup ID.
387   * @param  incremental             Indicates whether to perform an incremental
388   *                                 backup rather than a full backup.
389   * @param  incrementalBaseID       The backup ID of the existing backup on
390   *                                 which to base the incremental backup.  It
391   *                                 may be {@code null} if this is not an
392   *                                 incremental backup or if it should be based
393   *                                 on the most recent backup.
394   * @param  compress                Indicates whether the backup should be
395   *                                 compressed.
396   * @param  encrypt                 Indicates whether the backup should be
397   *                                 encrypted.
398   * @param  hash                    Indicates whether to generate a hash of the
399   *                                 backup contents.
400   * @param  signHash                Indicates whether to sign the hash of the
401   *                                 backup contents.
402   * @param  scheduledStartTime      The time that this task should start
403   *                                 running.
404   * @param  dependencyIDs           The list of task IDs that will be required
405   *                                 to complete before this task will be
406   *                                 eligible to start.
407   * @param  failedDependencyAction  Indicates what action should be taken if
408   *                                 any of the dependencies for this task do
409   *                                 not complete successfully.
410   * @param  notifyOnCompletion      The list of e-mail addresses of individuals
411   *                                 that should be notified when this task
412   *                                 completes.
413   * @param  notifyOnError           The list of e-mail addresses of individuals
414   *                                 that should be notified if this task does
415   *                                 not complete successfully.
416   */
417  public BackupTask(final String taskID, final String backupDirectory,
418                    final List<String> backendIDs, final String backupID,
419                    final boolean incremental, final String incrementalBaseID,
420                    final boolean compress, final boolean encrypt,
421                    final boolean hash, final boolean signHash,
422                    final Date scheduledStartTime,
423                    final List<String> dependencyIDs,
424                    final FailedDependencyAction failedDependencyAction,
425                    final List<String> notifyOnCompletion,
426                    final List<String> notifyOnError)
427  {
428    super(taskID, BACKUP_TASK_CLASS, scheduledStartTime,
429          dependencyIDs, failedDependencyAction, notifyOnCompletion,
430          notifyOnError);
431
432    ensureNotNull(backupDirectory);
433
434    this.backupDirectory   = backupDirectory;
435    this.backupID          = backupID;
436    this.incremental       = incremental;
437    this.incrementalBaseID = incrementalBaseID;
438    this.compress          = compress;
439    this.encrypt           = encrypt;
440    this.hash              = hash;
441    this.signHash          = signHash;
442
443    if (backendIDs == null)
444    {
445      this.backendIDs = Collections.emptyList();
446    }
447    else
448    {
449      this.backendIDs = Collections.unmodifiableList(backendIDs);
450    }
451  }
452
453
454
455  /**
456   * Creates a new backup task from the provided entry.
457   *
458   * @param  entry  The entry to use to create this backup task.
459   *
460   * @throws  TaskException  If the provided entry cannot be parsed as a backup
461   *                         task entry.
462   */
463  public BackupTask(final Entry entry)
464         throws TaskException
465  {
466    super(entry);
467
468
469    // Get the backup directory.  It must be present.
470    backupDirectory = entry.getAttributeValue(ATTR_BACKUP_DIRECTORY);
471    if (backupDirectory == null)
472    {
473      throw new TaskException(ERR_BACKUP_NO_BACKUP_DIRECTORY.get(
474                                   getTaskEntryDN()));
475    }
476
477
478    // Get the set of backend IDs.  It may be absent.
479    backendIDs = parseStringList(entry, ATTR_BACKEND_ID);
480
481
482    // Get the backup ID.  It may be absent.
483    backupID = entry.getAttributeValue(ATTR_BACKUP_ID);
484
485
486    // Get the incremental flag.  It may be absent.
487    incremental = parseBooleanValue(entry, ATTR_INCREMENTAL, false);
488
489
490    // Get the incremental base ID.  It may be absent.
491    incrementalBaseID = entry.getAttributeValue(ATTR_INCREMENTAL_BASE_ID);
492
493
494    // Determine whether to compress the backup.  It may be absent.
495    compress = parseBooleanValue(entry, ATTR_COMPRESS, false);
496
497
498    // Determine whether to encrypt the backup.  It may be absent.
499    encrypt = parseBooleanValue(entry, ATTR_ENCRYPT, false);
500
501
502    // Determine whether to hash the backup.  It may be absent.
503    hash = parseBooleanValue(entry, ATTR_HASH, false);
504
505
506    // Determine whether to sign the hash.  It may be absent.
507    signHash = parseBooleanValue(entry, ATTR_SIGN_HASH, false);
508  }
509
510
511
512  /**
513   * Creates a new backup task from the provided set of task properties.
514   *
515   * @param  properties  The set of task properties and their corresponding
516   *                     values to use for the task.  It must not be
517   *                     {@code null}.
518   *
519   * @throws  TaskException  If the provided set of properties cannot be used to
520   *                         create a valid backup task.
521   */
522  public BackupTask(final Map<TaskProperty,List<Object>> properties)
523         throws TaskException
524  {
525    super(BACKUP_TASK_CLASS, properties);
526
527    boolean  c     = false;
528    boolean  e     = false;
529    boolean  h     = false;
530    boolean  i     = false;
531    boolean  s     = false;
532    String   bDir  = null;
533    String   bkID  = null;
534    String   incID = null;
535    String[] beIDs = StaticUtils.NO_STRINGS;
536
537    for (final Map.Entry<TaskProperty,List<Object>> entry :
538         properties.entrySet())
539    {
540      final TaskProperty p = entry.getKey();
541      final String attrName = p.getAttributeName();
542      final List<Object> values = entry.getValue();
543
544      if (attrName.equalsIgnoreCase(ATTR_BACKUP_DIRECTORY))
545      {
546        bDir = parseString(p, values, bDir);
547      }
548      else if (attrName.equalsIgnoreCase(ATTR_BACKEND_ID))
549      {
550        beIDs = parseStrings(p, values, beIDs);
551      }
552      else if (attrName.equalsIgnoreCase(ATTR_BACKUP_ID))
553      {
554        bkID = parseString(p, values, bkID);
555      }
556      else if (attrName.equalsIgnoreCase(ATTR_INCREMENTAL))
557      {
558        i = parseBoolean(p, values, i);
559      }
560      else if (attrName.equalsIgnoreCase(ATTR_INCREMENTAL_BASE_ID))
561      {
562        incID = parseString(p, values, incID);
563      }
564      else if (attrName.equalsIgnoreCase(ATTR_COMPRESS))
565      {
566        c = parseBoolean(p, values, c);
567      }
568      else if (attrName.equalsIgnoreCase(ATTR_ENCRYPT))
569      {
570        e = parseBoolean(p, values, e);
571      }
572      else if (attrName.equalsIgnoreCase(ATTR_HASH))
573      {
574        h = parseBoolean(p, values, h);
575      }
576      else if (attrName.equalsIgnoreCase(ATTR_SIGN_HASH))
577      {
578        s = parseBoolean(p, values, s);
579      }
580    }
581
582    if (bDir == null)
583    {
584      throw new TaskException(ERR_BACKUP_NO_BACKUP_DIRECTORY.get(
585                                   getTaskEntryDN()));
586    }
587
588    backupDirectory   = bDir;
589    backendIDs        = Arrays.asList(beIDs);
590    backupID          = bkID;
591    incremental       = i;
592    incrementalBaseID = incID;
593    compress          = c;
594    encrypt           = e;
595    hash              = h;
596    signHash          = s;
597  }
598
599
600
601  /**
602   * {@inheritDoc}
603   */
604  @Override()
605  public String getTaskName()
606  {
607    return INFO_TASK_NAME_BACKUP.get();
608  }
609
610
611
612  /**
613   * {@inheritDoc}
614   */
615  @Override()
616  public String getTaskDescription()
617  {
618    return INFO_TASK_DESCRIPTION_BACKUP.get();
619  }
620
621
622
623  /**
624   * Retrieves the path to the backup directory in which the backup files should
625   * be written.  If a single backend is to be archived, then this will be the
626   * directory in which the backup files are written.  If multiple backends are
627   * to be archived, then this will be the parent of the directories containing
628   * the backups for each backend.
629   *
630   * @return  The path to the backup directory in which the backup files should
631   *          be written.
632   */
633  public String getBackupDirectory()
634  {
635    return backupDirectory;
636  }
637
638
639
640  /**
641   * Indicates whether the server should back up all supported backends.
642   *
643   * @return  {@code true} if the server should back up all supported backends,
644   *          or {@code false} if it should back up a specified backend or set
645   *          of backends.
646   */
647  public boolean backupAll()
648  {
649    return backendIDs.isEmpty();
650  }
651
652
653
654  /**
655   * Retrieves the set of backend IDs for the backends that should be archived.
656   *
657   * @return  The set of backend IDs for the backends that should be archived,
658   *          or an empty list if the server should back up all supported
659   *          backends.
660   */
661  public List<String> getBackendIDs()
662  {
663    return backendIDs;
664  }
665
666
667
668  /**
669   * Retrieves the backup ID for the backup to generate.
670   *
671   * @return  The backup ID for the backup to generate, or {@code null} if the
672   *          server should generate a backup ID.
673   */
674  public String getBackupID()
675  {
676    return backupID;
677  }
678
679
680
681  /**
682   * Indicates whether the server should attempt to perform an incremental
683   * backup rather than a full backup.
684   *
685   * @return  {@code true} if the server should attempt to perform an
686   *          incremental backup, or {@code false} for a full backup.
687   */
688  public boolean incremental()
689  {
690    return incremental;
691  }
692
693
694
695  /**
696   * Retrieves the backup ID of the existing backup on which the incremental
697   * backup should be based.
698   *
699   * @return  The backup ID of the existing backup on which the incremental
700   *          backup should be based, or {@code null} if it is not an
701   *          incremental backup or the server should use the most recent
702   *          backup available as the base for the new incremental backup.
703   */
704  public String getIncrementalBaseID()
705  {
706    return incrementalBaseID;
707  }
708
709
710
711  /**
712   * Indicates whether the backup should be compressed.
713   *
714   * @return  {@code true} if the backup should be compressed, or {@code false}
715   *          if not.
716   */
717  public boolean compress()
718  {
719    return compress;
720  }
721
722
723
724  /**
725   * Indicates whether the backup should be encrypted.
726   *
727   * @return  {@code true} if the backup should be encrypted, or {@code false}
728   *          if not.
729   */
730  public boolean encrypt()
731  {
732    return encrypt;
733  }
734
735
736
737  /**
738   * Indicates whether the server should generate a hash of the backup.
739   *
740   * @return  {@code true} if the server should generate a hash of the backup,
741   *          or {@code false} if not.
742   */
743  public boolean hash()
744  {
745    return hash;
746  }
747
748
749
750  /**
751   * Indicates whether the server should sign the backup hash.
752   *
753   * @return  {@code true} if the server should sign the backup hash, or
754   *          {@code false} if not.
755   */
756  public boolean signHash()
757  {
758    return signHash;
759  }
760
761
762
763  /**
764   * {@inheritDoc}
765   */
766  @Override()
767  protected List<String> getAdditionalObjectClasses()
768  {
769    return Arrays.asList(OC_BACKUP_TASK);
770  }
771
772
773
774  /**
775   * {@inheritDoc}
776   */
777  @Override()
778  protected List<Attribute> getAdditionalAttributes()
779  {
780    final ArrayList<Attribute> attrs = new ArrayList<Attribute>(9);
781
782    attrs.add(new Attribute(ATTR_BACKUP_DIRECTORY, backupDirectory));
783    attrs.add(new Attribute(ATTR_INCREMENTAL,  String.valueOf(incremental)));
784    attrs.add(new Attribute(ATTR_COMPRESS, String.valueOf(compress)));
785    attrs.add(new Attribute(ATTR_ENCRYPT, String.valueOf(encrypt)));
786    attrs.add(new Attribute(ATTR_HASH, String.valueOf(hash)));
787    attrs.add(new Attribute(ATTR_SIGN_HASH, String.valueOf(signHash)));
788
789    if (backendIDs.isEmpty())
790    {
791      attrs.add(new Attribute(ATTR_BACKUP_ALL, "true"));
792    }
793    else
794    {
795      attrs.add(new Attribute(ATTR_BACKEND_ID, backendIDs));
796    }
797
798    if (backupID != null)
799    {
800      attrs.add(new Attribute(ATTR_BACKUP_ID, backupID));
801    }
802
803    if (incrementalBaseID != null)
804    {
805      attrs.add(new Attribute(ATTR_INCREMENTAL_BASE_ID, incrementalBaseID));
806    }
807
808    return attrs;
809  }
810
811
812
813  /**
814   * {@inheritDoc}
815   */
816  @Override()
817  public List<TaskProperty> getTaskSpecificProperties()
818  {
819    final List<TaskProperty> propList = Arrays.asList(
820         PROPERTY_BACKUP_DIRECTORY,
821         PROPERTY_BACKEND_ID,
822         PROPERTY_BACKUP_ID,
823         PROPERTY_INCREMENTAL,
824         PROPERTY_INCREMENTAL_BASE_ID,
825         PROPERTY_COMPRESS,
826         PROPERTY_ENCRYPT,
827         PROPERTY_HASH,
828         PROPERTY_SIGN_HASH);
829
830    return Collections.unmodifiableList(propList);
831  }
832
833
834
835  /**
836   * {@inheritDoc}
837   */
838  @Override()
839  public Map<TaskProperty,List<Object>> getTaskPropertyValues()
840  {
841    final LinkedHashMap<TaskProperty,List<Object>> props =
842         new LinkedHashMap<TaskProperty,List<Object>>();
843
844    props.put(PROPERTY_BACKUP_DIRECTORY,
845         Collections.<Object>unmodifiableList(Arrays.asList(backupDirectory)));
846
847    props.put(PROPERTY_BACKEND_ID,
848              Collections.<Object>unmodifiableList(backendIDs));
849
850    if (backupID == null)
851    {
852      props.put(PROPERTY_BACKUP_ID, Collections.emptyList());
853    }
854    else
855    {
856      props.put(PROPERTY_BACKUP_ID,
857                Collections.<Object>unmodifiableList(Arrays.asList(backupID)));
858    }
859
860    props.put(PROPERTY_INCREMENTAL,
861              Collections.<Object>unmodifiableList(Arrays.asList(incremental)));
862
863    if (incrementalBaseID == null)
864    {
865      props.put(PROPERTY_INCREMENTAL_BASE_ID, Collections.emptyList());
866    }
867    else
868    {
869      props.put(PROPERTY_INCREMENTAL_BASE_ID,
870                Collections.<Object>unmodifiableList(Arrays.asList(
871                     incrementalBaseID)));
872    }
873
874    props.put(PROPERTY_COMPRESS,
875              Collections.<Object>unmodifiableList(Arrays.asList(compress)));
876
877    props.put(PROPERTY_ENCRYPT,
878              Collections.<Object>unmodifiableList(Arrays.asList(encrypt)));
879
880    props.put(PROPERTY_HASH,
881              Collections.<Object>unmodifiableList(Arrays.asList(hash)));
882
883    props.put(PROPERTY_SIGN_HASH,
884              Collections.<Object>unmodifiableList(Arrays.asList(signHash)));
885
886    props.putAll(super.getTaskPropertyValues());
887    return Collections.unmodifiableMap(props);
888  }
889}