001/*
002 * Copyright 2008-2024 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 2008-2024 Ping Identity Corporation
007 *
008 * Licensed under the Apache License, Version 2.0 (the "License");
009 * you may not use this file except in compliance with the License.
010 * You may obtain a copy of the License at
011 *
012 *    http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing, software
015 * distributed under the License is distributed on an "AS IS" BASIS,
016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017 * See the License for the specific language governing permissions and
018 * limitations under the License.
019 */
020/*
021 * Copyright (C) 2008-2024 Ping Identity Corporation
022 *
023 * This program is free software; you can redistribute it and/or modify
024 * it under the terms of the GNU General Public License (GPLv2 only)
025 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
026 * as published by the Free Software Foundation.
027 *
028 * This program is distributed in the hope that it will be useful,
029 * but WITHOUT ANY WARRANTY; without even the implied warranty of
030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
031 * GNU General Public License for more details.
032 *
033 * You should have received a copy of the GNU General Public License
034 * along with this program; if not, see <http://www.gnu.org/licenses>.
035 */
036package com.unboundid.ldap.sdk.unboundidds.tasks;
037
038
039
040import java.util.ArrayList;
041import java.util.Arrays;
042import java.util.Collections;
043import java.util.Date;
044import java.util.LinkedHashMap;
045import java.util.List;
046import java.util.Map;
047
048import com.unboundid.ldap.sdk.Attribute;
049import com.unboundid.ldap.sdk.Entry;
050import com.unboundid.util.NotMutable;
051import com.unboundid.util.NotNull;
052import com.unboundid.util.Nullable;
053import com.unboundid.util.StaticUtils;
054import com.unboundid.util.ThreadSafety;
055import com.unboundid.util.ThreadSafetyLevel;
056import com.unboundid.util.Validator;
057
058import static com.unboundid.ldap.sdk.unboundidds.tasks.TaskMessages.*;
059
060
061
062/**
063 * This class defines a Directory Server task that can be used to restore a
064 * backup.
065 * <BR>
066 * <BLOCKQUOTE>
067 *   <B>NOTE:</B>  This class, and other classes within the
068 *   {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
069 *   supported for use against Ping Identity, UnboundID, and
070 *   Nokia/Alcatel-Lucent 8661 server products.  These classes provide support
071 *   for proprietary functionality or for external specifications that are not
072 *   considered stable or mature enough to be guaranteed to work in an
073 *   interoperable way with other types of LDAP servers.
074 * </BLOCKQUOTE>
075 * <BR>
076 * The properties that are available for use with this type of task include:
077 * <UL>
078 *   <LI>The path to the backup directory in which the backup resides.  This
079 *       must be provided when scheduling a new task of this type.</LI>
080 *   <LI>The backup ID of the backup to be restored.  If this is not provided
081 *       when scheduling an instance of this task, then the most recent backup
082 *       in the backup directory will be selected.</LI>
083 *   <LI>A flag that indicates whether to attempt to restore the backup or
084 *       only to verify it to determine whether it appears to be valid (e.g.,
085 *       validate the digest and/or signature, make sure that the backend
086 *       considers it valid, etc.).</LI>
087 *   <LI>The path to a file containing a passphrase to use to generate the
088 *       encryption key.</LI>
089 * </UL>
090
091 */
092@NotMutable()
093@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
094public final class RestoreTask
095       extends Task
096{
097  /**
098   * The fully-qualified name of the Java class that is used for the restore
099   * task.
100   */
101  @NotNull static final String RESTORE_TASK_CLASS =
102       "com.unboundid.directory.server.tasks.RestoreTask";
103
104
105
106  /**
107   * The name of the attribute used to specify the path to the backup directory
108   * containing the backup to restore.
109   */
110  @NotNull private static final String ATTR_BACKUP_DIRECTORY =
111       "ds-backup-directory-path";
112
113
114
115  /**
116   * The name of the attribute used to specify the backup ID of the backup to
117   * restore.
118   */
119  @NotNull private static final String ATTR_BACKUP_ID = "ds-backup-id";
120
121
122
123  /**
124   * The name of the attribute used to specify the path to a file that contains
125   * the passphrase to use to generate the encryption key.
126   */
127  @NotNull private static final String ATTR_ENCRYPTION_PASSPHRASE_FILE =
128       "ds-task-restore-encryption-passphrase-file";
129
130
131
132  /**
133   * The name of the attribute used to indicate whether to only verify the
134   * backup but not actually restore it.
135   */
136  @NotNull private static final String ATTR_VERIFY_ONLY =
137       "ds-task-restore-verify-only";
138
139
140
141  /**
142   * The name of the object class used in restore task entries.
143   */
144  @NotNull private static final String OC_RESTORE_TASK = "ds-task-restore";
145
146
147
148  /**
149   * The task property for the backup directory.
150   */
151  @NotNull private static final TaskProperty PROPERTY_BACKUP_DIRECTORY =
152       new TaskProperty(ATTR_BACKUP_DIRECTORY,
153                        INFO_DISPLAY_NAME_BACKUP_DIRECTORY.get(),
154                        INFO_DESCRIPTION_BACKUP_DIRECTORY_RESTORE.get(),
155                        String.class, true, false, false);
156
157
158
159  /**
160   * The task property for the backup ID.
161   */
162  @NotNull private static final TaskProperty PROPERTY_BACKUP_ID =
163       new TaskProperty(ATTR_BACKUP_ID, INFO_DISPLAY_NAME_BACKUP_ID.get(),
164                        INFO_DESCRIPTION_BACKUP_ID_RESTORE.get(), String.class,
165                        false, false, true);
166
167
168
169  /**
170   * The task property that will be used for the encryption passphrase file.
171   */
172  @NotNull private static final TaskProperty
173       PROPERTY_ENCRYPTION_PASSPHRASE_FILE = new TaskProperty(
174            ATTR_ENCRYPTION_PASSPHRASE_FILE,
175            INFO_DISPLAY_NAME_ENCRYPTION_PASSPHRASE_FILE.get(),
176            INFO_DESCRIPTION_ENCRYPTION_PASSPHRASE_FILE.get(),
177            String.class, false, false, true);
178
179
180
181  /**
182   * The task property for the verify only flag.
183   */
184  @NotNull private static final TaskProperty PROPERTY_VERIFY_ONLY =
185       new TaskProperty(ATTR_VERIFY_ONLY, INFO_DISPLAY_NAME_VERIFY_ONLY.get(),
186                        INFO_DESCRIPTION_VERIFY_ONLY.get(), Boolean.class,
187                        false, false, false);
188
189
190
191  /**
192   * The serial version UID for this serializable class.
193   */
194  private static final long serialVersionUID = -8441221098187125379L;
195
196
197
198  // Indicates whether to only verify the backup without restoring it.
199  private final boolean verifyOnly;
200
201  // The path to the backup directory containing the backup to restore.
202  @NotNull private final String backupDirectory;
203
204  // The path to a file containing the passphrase to use to generate the
205  // encryption key.
206  @Nullable private final String encryptionPassphraseFile;
207
208  // The backup ID of the backup to restore.
209  @Nullable private final String backupID;
210
211
212
213  /**
214   * Creates a new uninitialized restore task instance which should only be used
215   * for obtaining general information about this task, including the task name,
216   * description, and supported properties.  Attempts to use a task created with
217   * this constructor for any other reason will likely fail.
218   */
219  public RestoreTask()
220  {
221    verifyOnly = false;
222    backupDirectory = null;
223    backupID = null;
224    encryptionPassphraseFile = null;
225  }
226
227
228
229  /**
230   * Creates a new restore task with the provided information.
231   *
232   * @param  taskID           The task ID to use for this task.  If it is
233   *                          {@code null} then a UUID will be generated for use
234   *                          as the task ID.
235   * @param  backupDirectory  The path to the directory on the server containing
236   *                          the backup to restore.  It may be an absolute path
237   *                          or relative to the server root directory.  It must
238   *                          not be {@code null}.
239   * @param  backupID         The backup ID of the backup to restore.  If this
240   *                          is {@code null} then the most recent backup in the
241   *                          specified backup directory will be restored.
242   * @param  verifyOnly       Indicates whether to only verify the backup
243   *                          without restoring it.
244   */
245  public RestoreTask(@Nullable final String taskID,
246                     @NotNull final String backupDirectory,
247                     @Nullable final String backupID,
248                     final boolean verifyOnly)
249  {
250    this(taskID, backupDirectory, backupID, verifyOnly, null, null, null, null,
251         null);
252  }
253
254
255
256  /**
257   * Creates a new restore task with the provided information.
258   *
259   * @param  taskID                  The task ID to use for this task.  If it is
260   *                                 {@code null} then a UUID will be generated
261   *                                 for use as the task ID.
262   * @param  backupDirectory         The path to the directory on the server
263   *                                 containing the backup to restore.  It may
264   *                                 be an absolute path or relative to the
265   *                                 server root directory.  It must not be
266   *                                 {@code null}.
267   * @param  backupID                The backup ID of the backup to restore.  If
268   *                                 this is {@code null} then the most recent
269   *                                 backup in the specified backup directory
270   *                                 will be restored.
271   * @param  verifyOnly              Indicates whether to only verify the backup
272   *                                 without restoring it.
273   * @param  scheduledStartTime      The time that this task should start
274   *                                 running.
275   * @param  dependencyIDs           The list of task IDs that will be required
276   *                                 to complete before this task will be
277   *                                 eligible to start.
278   * @param  failedDependencyAction  Indicates what action should be taken if
279   *                                 any of the dependencies for this task do
280   *                                 not complete successfully.
281   * @param  notifyOnCompletion      The list of e-mail addresses of individuals
282   *                                 that should be notified when this task
283   *                                 completes.
284   * @param  notifyOnError           The list of e-mail addresses of individuals
285   *                                 that should be notified if this task does
286   *                                 not complete successfully.
287   */
288  public RestoreTask(@Nullable final String taskID,
289              @NotNull final String backupDirectory,
290              @Nullable final String backupID,
291              final boolean verifyOnly,
292              @Nullable final Date scheduledStartTime,
293              @Nullable final List<String> dependencyIDs,
294              @Nullable final FailedDependencyAction failedDependencyAction,
295              @Nullable final List<String> notifyOnCompletion,
296              @Nullable final List<String> notifyOnError)
297  {
298    this(taskID, backupDirectory, backupID, verifyOnly, null,
299         scheduledStartTime, dependencyIDs, failedDependencyAction,
300         notifyOnCompletion, notifyOnError);
301  }
302
303
304
305  /**
306   * Creates a new restore task with the provided information.
307   *
308   * @param  taskID                    The task ID to use for this task.  If it
309   *                                   is {@code null} then a UUID will be
310   *                                   generated for use as the task ID.
311   * @param  backupDirectory           The path to the directory on the server
312   *                                   containing the backup to restore.  It may
313   *                                   be an absolute path or relative to the
314   *                                   server root directory.  It must not be
315   *                                   {@code null}.
316   * @param  backupID                  The backup ID of the backup to restore.
317   *                                   If this is {@code null} then the most
318   *                                   recent backup in the specified backup
319   *                                   directory will be restored.
320   * @param  verifyOnly                Indicates whether to only verify the
321   *                                   backup without restoring it.
322   * @param  encryptionPassphraseFile  The path to a file containing the
323   *                                   passphrase to use to generate the
324   *                                   encryption key.  It amy be {@code null}
325   *                                   if the backup is not to be encrypted, or
326   *                                   if the key should be obtained in some
327   *                                   other way.
328   * @param  scheduledStartTime        The time that this task should start
329   *                                   running.
330   * @param  dependencyIDs             The list of task IDs that will be
331   *                                   required to complete before this task
332   *                                   will be eligible to start.
333   * @param  failedDependencyAction    Indicates what action should be taken if
334   *                                   any of the dependencies for this task do
335   *                                   not complete successfully.
336   * @param  notifyOnCompletion        The list of e-mail addresses of
337   *                                   individuals that should be notified when
338   *                                   this task completes.
339   * @param  notifyOnError             The list of e-mail addresses of
340   *                                   individuals that should be notified if
341   *                                   this task does not complete successfully.
342   */
343  public RestoreTask(@Nullable final String taskID,
344              @NotNull final String backupDirectory,
345              @Nullable final String backupID,
346              final boolean verifyOnly,
347              @Nullable final String encryptionPassphraseFile,
348              @Nullable final Date scheduledStartTime,
349              @Nullable final List<String> dependencyIDs,
350              @Nullable final FailedDependencyAction failedDependencyAction,
351              @Nullable final List<String> notifyOnCompletion,
352              @Nullable final List<String> notifyOnError)
353  {
354    this(taskID, backupDirectory, backupID, verifyOnly,
355         encryptionPassphraseFile, scheduledStartTime, dependencyIDs,
356         failedDependencyAction, null, notifyOnCompletion, null,
357         notifyOnError, null, null, null);
358  }
359
360
361
362  /**
363   * Creates a new restore task with the provided information.
364   *
365   * @param  taskID                    The task ID to use for this task.  If it
366   *                                   is {@code null} then a UUID will be
367   *                                   generated for use as the task ID.
368   * @param  backupDirectory           The path to the directory on the server
369   *                                   containing the backup to restore.  It may
370   *                                   be an absolute path or relative to the
371   *                                   server root directory.  It must not be
372   *                                   {@code null}.
373   * @param  backupID                  The backup ID of the backup to restore.
374   *                                   If this is {@code null} then the most
375   *                                   recent backup in the specified backup
376   *                                   directory will be restored.
377   * @param  verifyOnly                Indicates whether to only verify the
378   *                                   backup without restoring it.
379   * @param  encryptionPassphraseFile  The path to a file containing the
380   *                                   passphrase to use to generate the
381   *                                   encryption key.  It amy be {@code null}
382   *                                   if the backup is not to be encrypted, or
383   *                                   if the key should be obtained in some
384   *                                   other way.
385   * @param  scheduledStartTime        The time that this task should start
386   *                                   running.
387   * @param  dependencyIDs             The list of task IDs that will be
388   *                                   required to complete before this task
389   *                                   will be eligible to start.
390   * @param  failedDependencyAction    Indicates what action should be taken if
391   *                                   any of the dependencies for this task do
392   *                                   not complete successfully.
393   * @param  notifyOnStart           The list of e-mail addresses of individuals
394   *                                 that should be notified when this task
395   *                                 starts running.
396   * @param  notifyOnCompletion      The list of e-mail addresses of individuals
397   *                                 that should be notified when this task
398   *                                 completes.
399   * @param  notifyOnSuccess         The list of e-mail addresses of individuals
400   *                                 that should be notified if this task
401   *                                 completes successfully.
402   * @param  notifyOnError           The list of e-mail addresses of individuals
403   *                                 that should be notified if this task does
404   *                                 not complete successfully.
405   * @param  alertOnStart            Indicates whether the server should send an
406   *                                 alert notification when this task starts.
407   * @param  alertOnSuccess          Indicates whether the server should send an
408   *                                 alert notification if this task completes
409   *                                 successfully.
410   * @param  alertOnError            Indicates whether the server should send an
411   *                                 alert notification if this task fails to
412   *                                 complete successfully.
413   */
414  public RestoreTask(@Nullable final String taskID,
415              @NotNull final String backupDirectory,
416              @Nullable final String backupID,
417              final boolean verifyOnly,
418              @Nullable final String encryptionPassphraseFile,
419              @Nullable final Date scheduledStartTime,
420              @Nullable final List<String> dependencyIDs,
421              @Nullable final FailedDependencyAction failedDependencyAction,
422              @Nullable final List<String> notifyOnStart,
423              @Nullable final List<String> notifyOnCompletion,
424              @Nullable final List<String> notifyOnSuccess,
425              @Nullable final List<String> notifyOnError,
426              @Nullable final Boolean alertOnStart,
427              @Nullable final Boolean alertOnSuccess,
428              @Nullable final Boolean alertOnError)
429  {
430    super(taskID, RESTORE_TASK_CLASS, scheduledStartTime,
431         dependencyIDs, failedDependencyAction, notifyOnStart,
432         notifyOnCompletion, notifyOnSuccess, notifyOnError, alertOnStart,
433         alertOnSuccess, alertOnError);
434
435    Validator.ensureNotNull(backupDirectory);
436
437    this.backupDirectory = backupDirectory;
438    this.backupID = backupID;
439    this.verifyOnly = verifyOnly;
440    this.encryptionPassphraseFile = encryptionPassphraseFile;
441  }
442
443
444
445  /**
446   * Creates a new restore task from the provided entry.
447   *
448   * @param  entry  The entry to use to create this restore task.
449   *
450   * @throws  TaskException  If the provided entry cannot be parsed as a restore
451   *                         task entry.
452   */
453  public RestoreTask(@NotNull final Entry entry)
454         throws TaskException
455  {
456    super(entry);
457
458
459    // Get the backup directory.  It must be present.
460    backupDirectory = entry.getAttributeValue(ATTR_BACKUP_DIRECTORY);
461    if (backupDirectory == null)
462    {
463      throw new TaskException(ERR_RESTORE_NO_BACKUP_DIRECTORY.get(
464                                   getTaskEntryDN()));
465    }
466
467
468    // Get the backup ID.  It may be absent.
469    backupID = entry.getAttributeValue(ATTR_BACKUP_ID);
470
471
472    // Get the verifyOnly flag.  It may be absent.
473    verifyOnly = parseBooleanValue(entry, ATTR_VERIFY_ONLY, false);
474
475
476    // Get the path to the encryption passphrase file.  It may be absent.
477    encryptionPassphraseFile =
478         entry.getAttributeValue(ATTR_ENCRYPTION_PASSPHRASE_FILE);
479  }
480
481
482
483  /**
484   * Creates a new restore task from the provided set of task properties.
485   *
486   * @param  properties  The set of task properties and their corresponding
487   *                     values to use for the task.  It must not be
488   *                     {@code null}.
489   *
490   * @throws  TaskException  If the provided set of properties cannot be used to
491   *                         create a valid restore task.
492   */
493  public RestoreTask(@NotNull final Map<TaskProperty,List<Object>> properties)
494         throws TaskException
495  {
496    super(RESTORE_TASK_CLASS, properties);
497
498    boolean v = false;
499    String  b = null;
500    String  f = null;
501    String  i = null;
502
503    for (final Map.Entry<TaskProperty,List<Object>> entry :
504         properties.entrySet())
505    {
506      final TaskProperty p = entry.getKey();
507      final String attrName = p.getAttributeName();
508      final List<Object> values = entry.getValue();
509
510      if (attrName.equalsIgnoreCase(ATTR_BACKUP_DIRECTORY))
511      {
512        b = parseString(p, values, b);
513      }
514      else if (attrName.equalsIgnoreCase(ATTR_BACKUP_ID))
515      {
516        i = parseString(p, values, i);
517      }
518      else if (attrName.equalsIgnoreCase(ATTR_VERIFY_ONLY))
519      {
520        v = parseBoolean(p, values, v);
521      }
522      else if (attrName.equalsIgnoreCase(ATTR_ENCRYPTION_PASSPHRASE_FILE))
523      {
524        f = parseString(p, values, f);
525      }
526    }
527
528    if (b == null)
529    {
530      throw new TaskException(ERR_RESTORE_NO_BACKUP_DIRECTORY.get(
531                                   getTaskEntryDN()));
532    }
533
534    backupDirectory = b;
535    backupID = i;
536    verifyOnly = v;
537    encryptionPassphraseFile = f;
538  }
539
540
541
542  /**
543   * {@inheritDoc}
544   */
545  @Override()
546  @NotNull()
547  public String getTaskName()
548  {
549    return INFO_TASK_NAME_RESTORE.get();
550  }
551
552
553
554  /**
555   * {@inheritDoc}
556   */
557  @Override()
558  @NotNull()
559  public String getTaskDescription()
560  {
561    return INFO_TASK_DESCRIPTION_RESTORE.get();
562  }
563
564
565
566  /**
567   * Retrieves the path to the backup directory which contains the backup to
568   * restore.  It may be either an absolute path or one that is relative to the
569   * server root.
570   *
571   * @return  The path to the backup directory which contains the backup to
572   *          restore.
573   */
574  @NotNull()
575  public String getBackupDirectory()
576  {
577    return backupDirectory;
578  }
579
580
581
582  /**
583   * Retrieves the backup ID of the backup to restore.
584   *
585   * @return  The backup ID of the backup to restore, or {@code null} if the
586   *          most recent backup in the backup directory should be restored.
587   */
588  @Nullable()
589  public String getBackupID()
590  {
591    return backupID;
592  }
593
594
595
596  /**
597   * Indicates whether the backup should only be verified without actually being
598   * restored.
599   *
600   * @return  {@code true} if the backup should be verified but not restored, or
601   *          {@code false} if it should be restored.
602   */
603  public boolean verifyOnly()
604  {
605    return verifyOnly;
606  }
607
608
609
610  /**
611   * Retrieves the path to a file that contains the passphrase to use to
612   * generate the encryption key.
613   *
614   * @return  The path to a file that contains the passphrase to use to
615   *          generate the encryption key, or {@code null} if the backup is
616   *          not encrypted or if the encryption key should be obtained through
617   *          some other means.
618   */
619  @Nullable()
620  public String getEncryptionPassphraseFile()
621  {
622    return encryptionPassphraseFile;
623  }
624
625
626
627  /**
628   * {@inheritDoc}
629   */
630  @Override()
631  @NotNull()
632  protected List<String> getAdditionalObjectClasses()
633  {
634    return Collections.singletonList(OC_RESTORE_TASK);
635  }
636
637
638
639  /**
640   * {@inheritDoc}
641   */
642  @Override()
643  @NotNull()
644  protected List<Attribute> getAdditionalAttributes()
645  {
646    final ArrayList<Attribute> attrs = new ArrayList<>(10);
647
648    attrs.add(new Attribute(ATTR_BACKUP_DIRECTORY, backupDirectory));
649    attrs.add(new Attribute(ATTR_VERIFY_ONLY, String.valueOf(verifyOnly)));
650
651    if (backupID != null)
652    {
653      attrs.add(new Attribute(ATTR_BACKUP_ID, backupID));
654    }
655
656    if (encryptionPassphraseFile != null)
657    {
658      attrs.add(new Attribute(ATTR_ENCRYPTION_PASSPHRASE_FILE,
659           encryptionPassphraseFile));
660    }
661
662    return attrs;
663  }
664
665
666
667  /**
668   * {@inheritDoc}
669   */
670  @Override()
671  @NotNull()
672  public List<TaskProperty> getTaskSpecificProperties()
673  {
674    final List<TaskProperty> propList = Arrays.asList(
675         PROPERTY_BACKUP_DIRECTORY,
676         PROPERTY_BACKUP_ID,
677         PROPERTY_VERIFY_ONLY,
678         PROPERTY_ENCRYPTION_PASSPHRASE_FILE);
679
680    return Collections.unmodifiableList(propList);
681  }
682
683
684
685  /**
686   * {@inheritDoc}
687   */
688  @Override()
689  @NotNull()
690  public Map<TaskProperty,List<Object>> getTaskPropertyValues()
691  {
692    final LinkedHashMap<TaskProperty,List<Object>> props =
693         new LinkedHashMap<>(StaticUtils.computeMapCapacity(10));
694
695    props.put(PROPERTY_BACKUP_DIRECTORY,
696         Collections.<Object>singletonList(backupDirectory));
697
698    if (backupID == null)
699    {
700      props.put(PROPERTY_BACKUP_ID, Collections.emptyList());
701    }
702    else
703    {
704      props.put(PROPERTY_BACKUP_ID,
705                Collections.<Object>singletonList(backupID));
706    }
707
708    props.put(PROPERTY_VERIFY_ONLY,
709              Collections.<Object>singletonList(verifyOnly));
710
711    if (encryptionPassphraseFile == null)
712    {
713      props.put(PROPERTY_ENCRYPTION_PASSPHRASE_FILE, Collections.emptyList());
714    }
715    else
716    {
717      props.put(PROPERTY_ENCRYPTION_PASSPHRASE_FILE,
718         Collections.<Object>singletonList(encryptionPassphraseFile));
719    }
720
721    props.putAll(super.getTaskPropertyValues());
722    return Collections.unmodifiableMap(props);
723  }
724}