001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions Copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2006-2009 Sun Microsystems, Inc. 015 * Portions Copyright 2013-2016 ForgeRock AS. 016 */ 017package org.opends.server.tools; 018 019import static org.opends.messages.ToolMessages.*; 020import static org.opends.server.config.ConfigConstants.*; 021import static org.opends.server.util.ServerConstants.*; 022import static org.opends.server.util.StaticUtils.*; 023import static com.forgerock.opendj.cli.ArgumentConstants.*; 024import static com.forgerock.opendj.cli.CommonArguments.*; 025import static com.forgerock.opendj.cli.Utils.*; 026 027import java.io.File; 028import java.io.OutputStream; 029import java.io.PrintStream; 030import java.text.SimpleDateFormat; 031import java.util.ArrayList; 032import java.util.Date; 033import java.util.HashMap; 034import java.util.HashSet; 035import java.util.List; 036import java.util.Map; 037import java.util.TimeZone; 038 039import org.forgerock.i18n.slf4j.LocalizedLogger; 040import org.forgerock.opendj.config.server.ConfigException; 041import org.forgerock.opendj.ldap.DN; 042import org.forgerock.opendj.server.config.server.BackendCfg; 043import org.forgerock.util.Utils; 044import org.opends.server.api.Backend; 045import org.opends.server.api.Backend.BackendOperation; 046import org.opends.server.core.DirectoryServer; 047import org.opends.server.core.LockFileManager; 048import org.opends.server.loggers.JDKLogging; 049import org.opends.server.protocols.ldap.LDAPAttribute; 050import org.opends.server.tasks.BackupTask; 051import org.opends.server.tools.tasks.TaskTool; 052import org.opends.server.types.BackupConfig; 053import org.opends.server.types.BackupDirectory; 054import org.opends.server.types.DirectoryException; 055import org.opends.server.types.InitializationException; 056import org.opends.server.types.NullOutputStream; 057import org.opends.server.types.RawAttribute; 058import org.opends.server.util.cli.LDAPConnectionArgumentParser; 059 060import com.forgerock.opendj.cli.Argument; 061import com.forgerock.opendj.cli.ArgumentException; 062import com.forgerock.opendj.cli.BooleanArgument; 063import com.forgerock.opendj.cli.ClientException; 064import com.forgerock.opendj.cli.StringArgument; 065 066/** 067 * This program provides a utility that may be used to back up a Directory 068 * Server backend in a binary form that may be quickly archived and restored. 069 * The format of the backup may vary based on the backend type and does not need 070 * to be something that can be handled by any other backend type. This will be 071 * a process that is intended to run separate from Directory Server and not 072 * internally within the server process (e.g., via the tasks interface). 073 */ 074public class BackUpDB extends TaskTool 075{ 076 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 077 078 /** 079 * The main method for BackUpDB tool. 080 * 081 * @param args The command-line arguments provided to this program. 082 */ 083 public static void main(String[] args) 084 { 085 int retCode = mainBackUpDB(args, true, System.out, System.err); 086 087 if(retCode != 0) 088 { 089 System.exit(filterExitCode(retCode)); 090 } 091 } 092 093 /** 094 * Processes the command-line arguments and invokes the backup process. 095 * 096 * @param args The command-line arguments provided to this 097 * program. 098 * @param initializeServer Indicates whether to initialize the server. 099 * @param outStream The output stream to use for standard output, or 100 * {@code null} if standard output is not needed. 101 * @param errStream The output stream to use for standard error, or 102 * {@code null} if standard error is not needed. 103 * 104 * @return The error code. 105 */ 106 public static int mainBackUpDB(String[] args, boolean initializeServer, 107 OutputStream outStream, OutputStream errStream) 108 { 109 BackUpDB tool = new BackUpDB(); 110 return tool.process(args, initializeServer, outStream, errStream); 111 } 112 113 /** Define the command-line arguments that may be used with this program. */ 114 private BooleanArgument backUpAll; 115 private BooleanArgument compress; 116 private BooleanArgument encrypt; 117 private BooleanArgument hash; 118 private BooleanArgument incremental; 119 private BooleanArgument signHash; 120 private StringArgument backendID; 121 private StringArgument backupIDString; 122 private StringArgument configFile; 123 private StringArgument backupDirectory; 124 private StringArgument incrementalBaseID; 125 126 private int process(String[] args, boolean initializeServer, 127 OutputStream outStream, OutputStream errStream) 128 { 129 PrintStream out = NullOutputStream.wrapOrNullStream(outStream); 130 PrintStream err = NullOutputStream.wrapOrNullStream(errStream); 131 JDKLogging.disableLogging(); 132 133 // Create the command-line argument parser for use with this program. 134 LDAPConnectionArgumentParser argParser = 135 createArgParser("org.opends.server.tools.BackUpDB", 136 INFO_BACKUPDB_TOOL_DESCRIPTION.get()); 137 argParser.setShortToolDescription(REF_SHORT_DESC_BACKUP.get()); 138 139 // Initialize all the command-line argument types and register them with the parser. 140 try 141 { 142 configFile = 143 StringArgument.builder("configFile") 144 .shortIdentifier('f') 145 .description(INFO_DESCRIPTION_CONFIG_FILE.get()) 146 .hidden() 147 .required() 148 .valuePlaceholder(INFO_CONFIGFILE_PLACEHOLDER.get()) 149 .buildAndAddToParser(argParser); 150 backendID = 151 StringArgument.builder("backendID") 152 .shortIdentifier('n') 153 .description(INFO_BACKUPDB_DESCRIPTION_BACKEND_ID.get()) 154 .multiValued() 155 .valuePlaceholder(INFO_BACKENDNAME_PLACEHOLDER.get()) 156 .buildAndAddToParser(argParser); 157 backUpAll = 158 BooleanArgument.builder("backUpAll") 159 .shortIdentifier('a') 160 .description(INFO_BACKUPDB_DESCRIPTION_BACKUP_ALL.get()) 161 .buildAndAddToParser(argParser); 162 backupIDString = 163 StringArgument.builder("backupID") 164 .shortIdentifier('I') 165 .description(INFO_BACKUPDB_DESCRIPTION_BACKUP_ID.get()) 166 .valuePlaceholder(INFO_BACKUPID_PLACEHOLDER.get()) 167 .buildAndAddToParser(argParser); 168 backupDirectory = 169 StringArgument.builder("backupDirectory") 170 .shortIdentifier('d') 171 .description(INFO_BACKUPDB_DESCRIPTION_BACKUP_DIR.get()) 172 .required() 173 .valuePlaceholder(INFO_BACKUPDIR_PLACEHOLDER.get()) 174 .buildAndAddToParser(argParser); 175 incremental = 176 BooleanArgument.builder("incremental") 177 .shortIdentifier('i') 178 .description(INFO_BACKUPDB_DESCRIPTION_INCREMENTAL.get()) 179 .buildAndAddToParser(argParser); 180 incrementalBaseID = 181 StringArgument.builder("incrementalBaseID") 182 .shortIdentifier('B') 183 .description(INFO_BACKUPDB_DESCRIPTION_INCREMENTAL_BASE_ID.get()) 184 .valuePlaceholder(INFO_BACKUPID_PLACEHOLDER.get()) 185 .buildAndAddToParser(argParser); 186 compress = 187 BooleanArgument.builder(OPTION_LONG_COMPRESS) 188 .shortIdentifier(OPTION_SHORT_COMPRESS) 189 .description(INFO_BACKUPDB_DESCRIPTION_COMPRESS.get()) 190 .buildAndAddToParser(argParser); 191 encrypt = 192 BooleanArgument.builder("encrypt") 193 .shortIdentifier('y') 194 .description(INFO_BACKUPDB_DESCRIPTION_ENCRYPT.get()) 195 .buildAndAddToParser(argParser); 196 hash = 197 BooleanArgument.builder("hash") 198 .shortIdentifier('A') 199 .description(INFO_BACKUPDB_DESCRIPTION_HASH.get()) 200 .buildAndAddToParser(argParser); 201 signHash = 202 BooleanArgument.builder("signHash") 203 .shortIdentifier('s') 204 .description(INFO_BACKUPDB_DESCRIPTION_SIGN_HASH.get()) 205 .buildAndAddToParser(argParser); 206 207 final BooleanArgument displayUsage = showUsageArgument(); 208 argParser.addArgument(displayUsage); 209 argParser.setUsageArgument(displayUsage); 210 } 211 catch (ArgumentException ae) 212 { 213 printWrappedText(err, ERR_CANNOT_INITIALIZE_ARGS.get(ae.getMessage())); 214 return 1; 215 } 216 217 // Init the default values so that they can appear also on the usage. 218 argParser.getArguments().initArgumentsWithConfiguration(argParser); 219 220 // Parse the command-line arguments provided to this program. 221 try 222 { 223 argParser.parseArguments(args); 224 validateTaskArgs(); 225 } 226 catch (ArgumentException ae) 227 { 228 argParser.displayMessageAndUsageReference(err, ERR_ERROR_PARSING_ARGS.get(ae.getMessage())); 229 return 1; 230 } 231 catch (ClientException ce) 232 { 233 // No need to display the usage since the problem comes with a provided value. 234 printWrappedText(err, ce.getMessageObject()); 235 return 1; 236 } 237 238 // If we should just display usage or version information, 239 // then print it and exit. 240 if (argParser.usageOrVersionDisplayed()) 241 { 242 return 0; 243 } 244 245 // Make sure that either the backUpAll argument was provided or at least one 246 // backend ID was given. They are mutually exclusive. 247 if (backUpAll.isPresent()) 248 { 249 if (backendID.isPresent()) 250 { 251 argParser.displayMessageAndUsageReference(err, ERR_BACKUPDB_CANNOT_MIX_BACKUP_ALL_AND_BACKEND_ID.get( 252 backUpAll.getLongIdentifier(), backendID.getLongIdentifier())); 253 return 1; 254 } 255 } 256 else if (! backendID.isPresent()) 257 { 258 argParser.displayMessageAndUsageReference(err, ERR_BACKUPDB_NEED_BACKUP_ALL_OR_BACKEND_ID.get( 259 backUpAll.getLongIdentifier(), backendID.getLongIdentifier())); 260 return 1; 261 } 262 else 263 { 264 // Check that the backendID has not been expressed twice. 265 HashSet<String> backendIDLowerCase = new HashSet<>(); 266 HashSet<String> repeatedBackendIds = new HashSet<>(); 267 for (String id : backendID.getValues()) 268 { 269 String lId = id.toLowerCase(); 270 if (!backendIDLowerCase.add(lId)) 271 { 272 repeatedBackendIds.add(lId); 273 } 274 } 275 if (!repeatedBackendIds.isEmpty()) 276 { 277 argParser.displayMessageAndUsageReference(err, 278 ERR_BACKUPDB_REPEATED_BACKEND_ID.get(Utils.joinAsString(", ", repeatedBackendIds))); 279 return 1; 280 } 281 } 282 283 // If the incremental base ID was specified, then make sure it is an 284 // incremental backup. 285 if (incrementalBaseID.isPresent() && ! incremental.isPresent()) 286 { 287 argParser.displayMessageAndUsageReference(err, ERR_BACKUPDB_INCREMENTAL_BASE_REQUIRES_INCREMENTAL.get( 288 incrementalBaseID.getLongIdentifier(), incremental.getLongIdentifier())); 289 return 1; 290 } 291 292 // Encryption or signing requires the ADS backend be available for 293 // CryptoManager access to secret key entries. If no connection arguments 294 // are present, infer an offline backup. 295 if ((encrypt.isPresent() || signHash.isPresent()) 296 && ! argParser.connectionArgumentsPresent()) { 297 argParser.displayMessageAndUsageReference(err, ERR_BACKUPDB_ENCRYPT_OR_SIGN_REQUIRES_ONLINE.get( 298 encrypt.getLongIdentifier(), signHash.getLongIdentifier())); 299 return 1; 300 } 301 302 // If the signHash option was provided, then make sure that the hash option 303 // was given. 304 if (signHash.isPresent() && !hash.isPresent()) 305 { 306 argParser.displayMessageAndUsageReference(err, 307 ERR_BACKUPDB_SIGN_REQUIRES_HASH.get(signHash.getLongIdentifier(), hash.getLongIdentifier())); 308 return 1; 309 } 310 311 // Checks the version - if upgrade required, the tool is unusable 312 try 313 { 314 checkVersion(); 315 } 316 catch (InitializationException e) 317 { 318 printWrappedText(err, e.getMessage()); 319 return 1; 320 } 321 322 return process(argParser, initializeServer, out, err); 323 } 324 325 @Override 326 public void addTaskAttributes(List<RawAttribute> attributes) 327 { 328 addIfHasValue(attributes, ATTR_TASK_BACKUP_ALL, backUpAll); 329 addIfHasValue(attributes, ATTR_TASK_BACKUP_COMPRESS, compress); 330 addIfHasValue(attributes, ATTR_TASK_BACKUP_ENCRYPT, encrypt); 331 addIfHasValue(attributes, ATTR_TASK_BACKUP_HASH, hash); 332 addIfHasValue(attributes, ATTR_TASK_BACKUP_INCREMENTAL, incremental); 333 addIfHasValue(attributes, ATTR_TASK_BACKUP_SIGN_HASH, signHash); 334 335 List<String> backendIDs = backendID.getValues(); 336 if (backendIDs != null && !backendIDs.isEmpty()) { 337 attributes.add( 338 new LDAPAttribute(ATTR_TASK_BACKUP_BACKEND_ID, backendIDs)); 339 } 340 341 addIfHasValue(attributes, ATTR_BACKUP_ID, backupIDString); 342 addIfHasValue(attributes, ATTR_BACKUP_DIRECTORY_PATH, backupDirectory); 343 addIfHasValue(attributes, ATTR_TASK_BACKUP_INCREMENTAL_BASE_ID, incrementalBaseID); 344 } 345 346 private void addIfHasValue(List<RawAttribute> attributes, String attrName, Argument arg) 347 { 348 if (hasValueDifferentThanDefaultValue(arg)) { 349 attributes.add(new LDAPAttribute(attrName, arg.getValue())); 350 } 351 } 352 353 private boolean hasValueDifferentThanDefaultValue(Argument arg) 354 { 355 return arg.getValue() != null 356 && !arg.getValue().equals(arg.getDefaultValue()); 357 } 358 359 @Override 360 public String getTaskObjectclass() { 361 return "ds-task-backup"; 362 } 363 364 @Override 365 public Class<?> getTaskClass() { 366 return BackupTask.class; 367 } 368 369 @Override 370 protected int processLocal(boolean initializeServer, 371 PrintStream out, 372 PrintStream err) { 373 // Make sure that the backup directory exists. If not, then create it. 374 File backupDirFile = new File(backupDirectory.getValue()); 375 if (! backupDirFile.exists()) 376 { 377 try 378 { 379 backupDirFile.mkdirs(); 380 } 381 catch (Exception e) 382 { 383 printWrappedText( 384 err, ERR_BACKUPDB_CANNOT_CREATE_BACKUP_DIR.get(backupDirectory.getValue(), getExceptionMessage(e))); 385 return 1; 386 } 387 } 388 389 // If no backup ID was provided, then create one with the current timestamp. 390 String backupID; 391 if (backupIDString.isPresent()) 392 { 393 backupID = backupIDString.getValue(); 394 } 395 else 396 { 397 SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT_GMT_TIME); 398 dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); 399 backupID = dateFormat.format(new Date()); 400 } 401 402 // If the incremental base ID was specified, then make sure it is an 403 // incremental backup. 404 String incrementalBase; 405 if (incrementalBaseID.isPresent()) 406 { 407 incrementalBase = incrementalBaseID.getValue(); 408 } 409 else 410 { 411 incrementalBase = null; 412 } 413 414 if (initializeServer) 415 { 416 try 417 { 418 new DirectoryServer.InitializationBuilder(configFile.getValue()) 419 .requireErrorAndDebugLogPublisher(out, err) 420 .initialize(); 421 } 422 catch (InitializationException ie) 423 { 424 printWrappedText(err, ERR_CANNOT_INITIALIZE_SERVER_COMPONENTS.get(getExceptionMessage(ie))); 425 return 1; 426 } 427 } 428 429 430 // Get information about the backends defined in the server, and determine 431 // whether we are backing up multiple backends or a single backend. 432 List<Backend<?>> backendList = new ArrayList<>(); 433 List<BackendCfg> entryList = new ArrayList<>(); 434 List<List<DN>> dnList = new ArrayList<>(); 435 BackendToolUtils.getBackends(backendList, entryList, dnList); 436 int numBackends = backendList.size(); 437 438 boolean multiple; 439 List<Backend<?>> backendsToArchive = new ArrayList<>(numBackends); 440 Map<String, BackendCfg> configEntries = new HashMap<>(numBackends); 441 if (backUpAll.isPresent()) 442 { 443 for (int i=0; i < numBackends; i++) 444 { 445 Backend<?> b = backendList.get(i); 446 if (b.supports(BackendOperation.BACKUP)) 447 { 448 backendsToArchive.add(b); 449 configEntries.put(b.getBackendID(), entryList.get(i)); 450 } 451 } 452 453 // We'll proceed as if we're backing up multiple backends in this case 454 // even if there's just one. 455 multiple = true; 456 } 457 else 458 { 459 // Iterate through the set of backends and pick out those that were requested. 460 HashSet<String> requestedBackends = new HashSet<>(backendID.getValues()); 461 for (int i=0; i < numBackends; i++) 462 { 463 Backend<?> b = backendList.get(i); 464 if (requestedBackends.contains(b.getBackendID())) 465 { 466 if (b.supports(BackendOperation.BACKUP)) 467 { 468 backendsToArchive.add(b); 469 configEntries.put(b.getBackendID(), entryList.get(i)); 470 requestedBackends.remove(b.getBackendID()); 471 } 472 else 473 { 474 logger.warn(WARN_BACKUPDB_BACKUP_NOT_SUPPORTED, b.getBackendID()); 475 } 476 } 477 } 478 479 if (! requestedBackends.isEmpty()) 480 { 481 for (String id : requestedBackends) 482 { 483 logger.error(ERR_BACKUPDB_NO_BACKENDS_FOR_ID, id); 484 } 485 486 return 1; 487 } 488 489 // See if there are multiple backends to archive. 490 multiple = backendsToArchive.size() > 1; 491 } 492 493 // If there are no backends to archive, then print an error and exit. 494 if (backendsToArchive.isEmpty()) 495 { 496 logger.warn(WARN_BACKUPDB_NO_BACKENDS_TO_ARCHIVE); 497 return 1; 498 } 499 500 // Iterate through the backends to archive and back them up individually. 501 boolean errorsEncountered = false; 502 for (Backend<?> b : backendsToArchive) 503 { 504 if (!acquireSharedLock(b)) 505 { 506 errorsEncountered = true; 507 continue; 508 } 509 510 logger.info(NOTE_BACKUPDB_STARTING_BACKUP, b.getBackendID()); 511 512 // Get the config entry for this backend. 513 BackendCfg configEntry = configEntries.get(b.getBackendID()); 514 515 // Get the path to the directory to use for this backup. If we will be 516 // backing up multiple backends (or if we are backing up all backends, 517 // even if there's only one of them), then create a subdirectory for each 518 // backend. 519 String backupDirPath; 520 if (multiple) 521 { 522 backupDirPath = backupDirectory.getValue() + File.separator + 523 b.getBackendID(); 524 } 525 else 526 { 527 backupDirPath = backupDirectory.getValue(); 528 } 529 530 // If the directory doesn't exist, then create it. If it does exist, then 531 // see if it has a backup descriptor file. 532 BackupDirectory backupDir; 533 backupDirFile = new File(backupDirPath); 534 if (backupDirFile.exists()) 535 { 536 String descriptorPath = backupDirPath + File.separator + 537 BACKUP_DIRECTORY_DESCRIPTOR_FILE; 538 File descriptorFile = new File(descriptorPath); 539 if (descriptorFile.exists()) 540 { 541 try 542 { 543 backupDir = 544 BackupDirectory.readBackupDirectoryDescriptor(backupDirPath); 545 } 546 catch (ConfigException ce) 547 { 548 logger.error(ERR_BACKUPDB_CANNOT_PARSE_BACKUP_DESCRIPTOR, descriptorPath, ce.getMessage()); 549 errorsEncountered = true; 550 releaseSharedLock(b); 551 continue; 552 } 553 catch (Exception e) 554 { 555 logger.error(ERR_BACKUPDB_CANNOT_PARSE_BACKUP_DESCRIPTOR, descriptorPath, getExceptionMessage(e)); 556 errorsEncountered = true; 557 releaseSharedLock(b); 558 continue; 559 } 560 } 561 else 562 { 563 backupDir = new BackupDirectory(backupDirPath, configEntry.dn()); 564 } 565 } 566 else 567 { 568 try 569 { 570 backupDirFile.mkdirs(); 571 } 572 catch (Exception e) 573 { 574 logger.error(ERR_BACKUPDB_CANNOT_CREATE_BACKUP_DIR, backupDirPath, getExceptionMessage(e)); 575 errorsEncountered = true; 576 releaseSharedLock(b); 577 continue; 578 } 579 580 backupDir = new BackupDirectory(backupDirPath, configEntry.dn()); 581 } 582 583 // Create a backup configuration and determine whether the requested 584 // backup can be performed using the selected backend. 585 BackupConfig backupConfig = new BackupConfig(backupDir, backupID, 586 incremental.isPresent()); 587 backupConfig.setCompressData(compress.isPresent()); 588 backupConfig.setEncryptData(encrypt.isPresent()); 589 backupConfig.setHashData(hash.isPresent()); 590 backupConfig.setSignHash(signHash.isPresent()); 591 backupConfig.setIncrementalBaseID(incrementalBase); 592 593 if (!b.supports(BackendOperation.BACKUP)) 594 { 595 logger.error(ERR_BACKUPDB_CANNOT_BACKUP, b.getBackendID()); 596 errorsEncountered = true; 597 unlockBackend(b); 598 continue; 599 } 600 601 // Perform the backup. 602 try 603 { 604 b.createBackup(backupConfig); 605 } 606 catch (DirectoryException de) 607 { 608 logger.error(ERR_BACKUPDB_ERROR_DURING_BACKUP, b.getBackendID(), de.getMessageObject()); 609 errorsEncountered = true; 610 unlockBackend(b); 611 continue; 612 } 613 catch (Exception e) 614 { 615 logger.error(ERR_BACKUPDB_ERROR_DURING_BACKUP, b.getBackendID(), getExceptionMessage(e)); 616 errorsEncountered = true; 617 unlockBackend(b); 618 continue; 619 } 620 621 if (!releaseSharedLock(b)) 622 { 623 errorsEncountered = true; 624 } 625 } 626 627 // Print a final completed message, indicating whether there were any errors 628 // in the process. 629 if (errorsEncountered) 630 { 631 logger.info(NOTE_BACKUPDB_COMPLETED_WITH_ERRORS); 632 return 1; 633 } 634 logger.info(NOTE_BACKUPDB_COMPLETED_SUCCESSFULLY); 635 return 0; 636 } 637 638 private boolean acquireSharedLock(Backend<?> b) 639 { 640 try 641 { 642 String lockFile = LockFileManager.getBackendLockFileName(b); 643 StringBuilder failureReason = new StringBuilder(); 644 if (!LockFileManager.acquireSharedLock(lockFile, failureReason)) 645 { 646 logger.error(ERR_BACKUPDB_CANNOT_LOCK_BACKEND, b.getBackendID(), failureReason); 647 return false; 648 } 649 return true; 650 } 651 catch (Exception e) 652 { 653 logger.error(ERR_BACKUPDB_CANNOT_LOCK_BACKEND, b.getBackendID(), getExceptionMessage(e)); 654 return false; 655 } 656 } 657 658 private boolean releaseSharedLock(Backend<?> b) 659 { 660 try 661 { 662 String lockFile = LockFileManager.getBackendLockFileName(b); 663 StringBuilder failureReason = new StringBuilder(); 664 if (!LockFileManager.releaseLock(lockFile, failureReason)) 665 { 666 logger.warn(WARN_BACKUPDB_CANNOT_UNLOCK_BACKEND, b.getBackendID(), failureReason); 667 return false; 668 } 669 return true; 670 } 671 catch (Exception e) 672 { 673 logger.warn(WARN_BACKUPDB_CANNOT_UNLOCK_BACKEND, b.getBackendID(), getExceptionMessage(e)); 674 return false; 675 } 676 } 677 678 private void unlockBackend(Backend<?> b) 679 { 680 try 681 { 682 String lockFile = LockFileManager.getBackendLockFileName(b); 683 StringBuilder failureReason = new StringBuilder(); 684 if (!LockFileManager.releaseLock(lockFile, failureReason)) 685 { 686 logger.warn(WARN_BACKUPDB_CANNOT_UNLOCK_BACKEND, b.getBackendID(), failureReason); 687 } 688 } 689 catch (Exception e) 690 { 691 logger.warn(WARN_BACKUPDB_CANNOT_UNLOCK_BACKEND, b.getBackendID(), getExceptionMessage(e)); 692 } 693 } 694 695 @Override 696 public String getTaskId() { 697 return backupIDString != null ? backupIDString.getValue() : null; 698 } 699}