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