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