mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

abobrov
19.31.2008 ae9b70a92890b8175913884216131d4ca650fae9
- [Issue 3674] Task backend should support backup and export
4 files modified
876 ■■■■■ changed files
opends/src/messages/messages/backend.properties 77 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/backends/task/TaskBackend.java 771 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/types/LDIFExportConfig.java 20 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/util/ServerConstants.java 8 ●●●●● patch | view | raw | blame | history
opends/src/messages/messages/backend.properties
@@ -1056,3 +1056,80 @@
SEVERE_ERR_RECURRINGTASK_INVALID_TOKENS_COMBO_377=The provided recurring task \
 entry attribute %s holding the recurring task schedule has invalid tokens \
 combination yielding a nonexistent calendar date
SEVERE_ERR_TASKS_CANNOT_EXPORT_TO_FILE_378=An error occurred while \
 attempting to export task backend data:  %s
SEVERE_ERR_TASKS_BACKUP_CANNOT_GET_MAC_379=An error occurred while attempting \
 to obtain the %s MAC provider to create the signed hash for the backup:  %s
SEVERE_ERR_TASKS_BACKUP_CANNOT_GET_DIGEST_380=An error occurred while \
 attempting to obtain the %s message digest to create the hash for the backup: \
 %s
SEVERE_ERR_TASKS_BACKUP_CANNOT_CREATE_ARCHIVE_FILE_381=An error occurred \
 while trying to create the tasks archive file %s in directory %s:  %s
SEVERE_ERR_TASKS_BACKUP_CANNOT_GET_CIPHER_382=An error occurred while \
 attempting to obtain the cipher to use to encrypt the backup:  %s
SEVERE_ERR_TASKS_BACKUP_ZIP_COMMENT_383=%s tasks backup %s
SEVERE_ERR_TASKS_BACKUP_CANNOT_BACKUP_TASKS_FILE_384=An error occurred while \
 attempting to back up tasks file %s:  %s
SEVERE_ERR_TASKS_BACKUP_CANNOT_CLOSE_ZIP_STREAM_385=An error occurred while \
 trying to close the tasks archive file %s in directory %s:  %s
SEVERE_ERR_TASKS_BACKUP_CANNOT_UPDATE_BACKUP_DESCRIPTOR_386=An error occurred \
 while attempting to update the backup descriptor file %s with information \
 about the tasks backup:  %s
SEVERE_ERR_TASKS_RESTORE_NO_SUCH_BACKUP_387=Unable to restore or verify \
 tasks backup %s in directory %s because no such backup exists
SEVERE_ERR_TASKS_RESTORE_NO_BACKUP_FILE_388=Unable to restore or verify \
 tasks backup %s in directory %s because the archive filename could not be \
 determined
SEVERE_ERR_TASKS_RESTORE_NO_SUCH_FILE_389=Unable to restore or verify tasks \
 backup %s because the specified archive file %s does not exist
SEVERE_ERR_TASKS_RESTORE_CANNOT_CHECK_FOR_ARCHIVE_390=Unable to restore or \
 verify tasks backup %s because an error occurred while trying to determine \
 whether backup archive %s exists:  %s
SEVERE_ERR_TASKS_RESTORE_UNKNOWN_DIGEST_391=Unable to restore or verify \
 tasks backup %s because an unsigned hash of this backup is available but the \
 server cannot determine the digest algorithm used to generate this hash
SEVERE_ERR_TASKS_RESTORE_CANNOT_GET_DIGEST_392=Unable to restore or verify \
 tasks backup %s because it has an unsigned hash that uses an unknown or \
 unsupported digest algorithm of %s
SEVERE_ERR_TASKS_RESTORE_UNKNOWN_MAC_393=Unable to restore or verify tasks \
 backup %s because a signed hash of this backup is available but the server \
 cannot determine the MAC algorithm used to generate this hash
SEVERE_ERR_TASKS_RESTORE_CANNOT_GET_MAC_394=Unable to restore or verify \
 tasks backup %s because it has a signed hash that uses an unknown or \
 unsupported MAC algorithm of %s
SEVERE_ERR_TASKS_RESTORE_CANNOT_OPEN_BACKUP_FILE_395=Unable to restore or \
 verify tasks backup %s because an error occurred while attempting to open \
 the backup archive file %s:  %s
SEVERE_ERR_TASKS_RESTORE_CANNOT_GET_CIPHER_396=Unable to restore or verify \
 tasks backup %s because it is encrypted using an unknown or unsupported \
 cipher:  %s
SEVERE_ERR_TASKS_RESTORE_CANNOT_GET_ZIP_ENTRY_397=Unable to restore or verify \
 tasks backup %s because an error occurred while trying to read the next \
 entry from the archive file %s:  %s
SEVERE_ERR_TASKS_RESTORE_CANNOT_CREATE_FILE_398=Unable to restore tasks \
 backup %s because an error occurred while trying to recreate file %s:  %s
SEVERE_ERR_TASKS_RESTORE_CANNOT_PROCESS_ARCHIVE_FILE_399=Unable to restore or \
 verify tasks backup %s because an error occurred while processing archived \
 file %s:  %s
SEVERE_ERR_TASKS_RESTORE_ERROR_ON_ZIP_STREAM_CLOSE_400=Unable to restore or \
 verify tasks backup %s because an unexpected error occurred while trying to \
 close the archive file %s:  %s
NOTICE_TASKS_RESTORE_UNSIGNED_HASH_VALID_401=The message digest calculated \
 from the backup archive matches the digest stored with the backup information
SEVERE_ERR_TASKS_RESTORE_UNSIGNED_HASH_INVALID_402=Unable to restore or \
 verify tasks backup %s because the message digest calculated from the backup \
 archive does not match the digest stored with the backup information
NOTICE_TASKS_RESTORE_SIGNED_HASH_VALID_403=The signed digest calculated from \
 the backup archive matches the signature stored with the backup information
SEVERE_ERR_TASKS_RESTORE_SIGNED_HASH_INVALID_404=Unable to restore or verify \
 tasks backup %s because the signed digest calculated from the backup archive \
 does not match the signature stored with the backup information
NOTICE_TASKS_RESTORE_VERIFY_SUCCESSFUL_405=All tests performed on tasks \
 backup %s from directory %s show that the archive appears to be valid
NOTICE_TASKS_RESTORE_SUCCESSFUL_406=Tasks backup %s was successfully \
 restored from the archive in directory %s
SEVERE_ERR_BACKUP_MISSING_BACKUPID_407=The information for backup %s could \
 not be found in the backup directory %s
SEVERE_ERR_BACKUP_CANNOT_UPDATE_BACKUP_DESCRIPTOR_408=An error occurred \
 while attempting to update the backup descriptor file %s with information \
 about the backup:  %s
opends/src/server/org/opends/server/backends/task/TaskBackend.java
@@ -29,13 +29,26 @@
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.zip.Deflater;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import javax.crypto.Mac;
import org.opends.messages.Message;
import org.opends.server.admin.Configuration;
import org.opends.server.admin.server.ConfigurationChangeListener;
@@ -55,9 +68,12 @@
import org.opends.server.types.AttributeValue;
import org.opends.server.types.BackupConfig;
import org.opends.server.types.BackupDirectory;
import org.opends.server.types.BackupInfo;
import org.opends.server.types.CanceledOperationException;
import org.opends.server.types.ConditionResult;
import org.opends.server.types.ConfigChangeResult;
import org.opends.server.types.CryptoManager;
import org.opends.server.types.CryptoManagerException;
import org.opends.server.types.DebugLogLevel;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.DN;
@@ -74,12 +90,18 @@
import org.opends.server.types.ResultCode;
import org.opends.server.types.SearchFilter;
import org.opends.server.types.SearchScope;
import org.opends.server.util.DynamicConstants;
import org.opends.server.util.LDIFException;
import org.opends.server.util.LDIFReader;
import org.opends.server.util.LDIFWriter;
import org.opends.server.util.Validator;
import static org.opends.messages.BackendMessages.*;
import static org.opends.server.config.ConfigConstants.*;
import static org.opends.server.loggers.debug.DebugLogger.*;
import static org.opends.server.loggers.ErrorLogger.*;
import static org.opends.server.util.StaticUtils.*;
import static org.opends.server.util.ServerConstants.*;
@@ -1131,7 +1153,105 @@
  public void exportLDIF(LDIFExportConfig exportConfig)
         throws DirectoryException
  {
    // FIXME -- Implement support for exporting to LDIF.
    File taskFile = getFileForPath(taskBackingFile);
    // Read from.
    LDIFReader ldifReader;
    try
    {
      ldifReader = new LDIFReader(new LDIFImportConfig(taskFile.getPath()));
    }
    catch (Exception e)
    {
      Message message =
          ERR_TASKS_CANNOT_EXPORT_TO_FILE.get(String.valueOf(e));
      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
                                   message, e);
    }
    // Write to.
    LDIFWriter ldifWriter;
    try
    {
      ldifWriter = new LDIFWriter(exportConfig);
    }
    catch (Exception e)
    {
      if (debugEnabled())
      {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      Message message = ERR_TASKS_CANNOT_EXPORT_TO_FILE.get(
          stackTraceToSingleLineString(e));
      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
                                   message);
    }
    // Copy record by record.
    try
    {
      while (true)
      {
        Entry e = null;
        try
        {
          e = ldifReader.readEntry();
          if (e == null)
          {
            break;
          }
        }
        catch (LDIFException le)
        {
          if (! le.canContinueReading())
          {
            Message message =
                ERR_TASKS_CANNOT_EXPORT_TO_FILE.get(String.valueOf(e));
            throw new DirectoryException(
                           DirectoryServer.getServerErrorResultCode(),
                           message, le);
          }
          else
          {
            continue;
          }
        }
        ldifWriter.writeEntry(e);
      }
    }
    catch (Exception e)
    {
      if (debugEnabled())
      {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
    }
    finally
    {
      try
      {
        ldifWriter.close();
      }
      catch (Exception e)
      {
        if (debugEnabled())
        {
          TRACER.debugCaught(DebugLogLevel.ERROR, e);
        }
      }
      try
      {
        ldifReader.close();
      }
      catch (Exception e)
      {
        if (debugEnabled())
        {
          TRACER.debugCaught(DebugLogLevel.ERROR, e);
        }
      }
    }
  }
@@ -1194,7 +1314,294 @@
  public void createBackup(BackupConfig backupConfig)
         throws DirectoryException
  {
    // NYI -- Create the backup.
    // Get the properties to use for the backup.  We don't care whether or not
    // it's incremental, so there's no need to get that.
    String          backupID        = backupConfig.getBackupID();
    BackupDirectory backupDirectory = backupConfig.getBackupDirectory();
    boolean         compress        = backupConfig.compressData();
    boolean         encrypt         = backupConfig.encryptData();
    boolean         hash            = backupConfig.hashData();
    boolean         signHash        = backupConfig.signHash();
    // Create a hash map that will hold the extra backup property information
    // for this backup.
    HashMap<String,String> backupProperties = new HashMap<String,String>();
    // Get the crypto manager and use it to obtain references to the message
    // digest and/or MAC to use for hashing and/or signing.
    CryptoManager cryptoManager   = DirectoryServer.getCryptoManager();
    Mac           mac             = null;
    MessageDigest digest          = null;
    String        digestAlgorithm = null;
    String        macKeyID    = null;
    if (hash)
    {
      if (signHash)
      {
        try
        {
          macKeyID = cryptoManager.getMacEngineKeyEntryID();
          backupProperties.put(BACKUP_PROPERTY_MAC_KEY_ID, macKeyID);
          mac = cryptoManager.getMacEngine(macKeyID);
        }
        catch (Exception e)
        {
          if (debugEnabled())
          {
            TRACER.debugCaught(DebugLogLevel.ERROR, e);
          }
          Message message = ERR_TASKS_BACKUP_CANNOT_GET_MAC.get(
              macKeyID, stackTraceToSingleLineString(e));
          throw new DirectoryException(
                         DirectoryServer.getServerErrorResultCode(), message,
                         e);
        }
      }
      else
      {
        digestAlgorithm = cryptoManager.getPreferredMessageDigestAlgorithm();
        backupProperties.put(BACKUP_PROPERTY_DIGEST_ALGORITHM, digestAlgorithm);
        try
        {
          digest = cryptoManager.getPreferredMessageDigest();
        }
        catch (Exception e)
        {
          if (debugEnabled())
          {
            TRACER.debugCaught(DebugLogLevel.ERROR, e);
          }
          Message message = ERR_TASKS_BACKUP_CANNOT_GET_DIGEST.get(
              digestAlgorithm, stackTraceToSingleLineString(e));
          throw new DirectoryException(
                         DirectoryServer.getServerErrorResultCode(), message,
                         e);
        }
      }
    }
    // Create an output stream that will be used to write the archive file.  At
    // its core, it will be a file output stream to put a file on the disk.  If
    // we are to encrypt the data, then that file output stream will be wrapped
    // in a cipher output stream.  The resulting output stream will then be
    // wrapped by a zip output stream (which may or may not actually use
    // compression).
    String filename = null;
    OutputStream outputStream;
    try
    {
      filename = TASKS_BACKUP_BASE_FILENAME + backupID;
      File archiveFile = new File(backupDirectory.getPath() + File.separator +
                                  filename);
      if (archiveFile.exists())
      {
        int i=1;
        while (true)
        {
          archiveFile = new File(backupDirectory.getPath() + File.separator +
                                 filename  + "." + i);
          if (archiveFile.exists())
          {
            i++;
          }
          else
          {
            filename = filename + "." + i;
            break;
          }
        }
      }
      outputStream = new FileOutputStream(archiveFile, false);
      backupProperties.put(BACKUP_PROPERTY_ARCHIVE_FILENAME, filename);
    }
    catch (Exception e)
    {
      if (debugEnabled())
      {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      Message message = ERR_TASKS_BACKUP_CANNOT_CREATE_ARCHIVE_FILE.
          get(String.valueOf(filename), backupDirectory.getPath(),
              getExceptionMessage(e));
      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
                                   message, e);
    }
    // If we should encrypt the data, then wrap the output stream in a cipher
    // output stream.
    if (encrypt)
    {
      try
      {
        outputStream
                = cryptoManager.getCipherOutputStream(outputStream);
      }
      catch (CryptoManagerException e)
      {
        if (debugEnabled())
        {
          TRACER.debugCaught(DebugLogLevel.ERROR, e);
        }
        Message message = ERR_TASKS_BACKUP_CANNOT_GET_CIPHER.get(
                stackTraceToSingleLineString(e));
        throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
                                     message, e);
      }
    }
    // Wrap the file output stream in a zip output stream.
    ZipOutputStream zipStream = new ZipOutputStream(outputStream);
    Message message = ERR_TASKS_BACKUP_ZIP_COMMENT.get(
            DynamicConstants.PRODUCT_NAME,
            backupID);
    zipStream.setComment(String.valueOf(message));
    if (compress)
    {
      zipStream.setLevel(Deflater.DEFAULT_COMPRESSION);
    }
    else
    {
      zipStream.setLevel(Deflater.NO_COMPRESSION);
    }
    // Take tasks file and write it to the zip stream. If we
    // are using a hash or MAC, then calculate that as well.
    byte[] buffer = new byte[8192];
    File tasksFile = getFileForPath(taskBackingFile);
    String baseName = tasksFile.getName();
    // We'll put the name in the hash, too.
    if (hash) {
      if (signHash) {
        mac.update(getBytes(baseName));
      } else {
        digest.update(getBytes(baseName));
      }
    }
    InputStream inputStream = null;
    try {
      ZipEntry zipEntry = new ZipEntry(baseName);
      zipStream.putNextEntry(zipEntry);
      inputStream = new FileInputStream(tasksFile);
      while (true) {
        int bytesRead = inputStream.read(buffer);
        if (bytesRead < 0 || backupConfig.isCancelled()) {
          break;
        }
        if (hash) {
          if (signHash) {
            mac.update(buffer, 0, bytesRead);
          } else {
            digest.update(buffer, 0, bytesRead);
          }
        }
        zipStream.write(buffer, 0, bytesRead);
      }
      zipStream.closeEntry();
      inputStream.close();
    } catch (Exception e) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      try {
        inputStream.close();
      } catch (Exception e2) {
      }
      try {
        zipStream.close();
      } catch (Exception e2) {
      }
      message = ERR_TASKS_BACKUP_CANNOT_BACKUP_TASKS_FILE.get(baseName,
        stackTraceToSingleLineString(e));
      throw new DirectoryException(
        DirectoryServer.getServerErrorResultCode(),
        message, e);
    }
    // We're done writing the file, so close the zip stream (which should also
    // close the underlying stream).
    try
    {
      zipStream.close();
    }
    catch (Exception e)
    {
      if (debugEnabled())
      {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      message = ERR_TASKS_BACKUP_CANNOT_CLOSE_ZIP_STREAM.get(
          filename, backupDirectory.getPath(), stackTraceToSingleLineString(e));
      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
                                   message, e);
    }
    // Get the digest or MAC bytes if appropriate.
    byte[] digestBytes = null;
    byte[] macBytes    = null;
    if (hash)
    {
      if (signHash)
      {
        macBytes = mac.doFinal();
      }
      else
      {
        digestBytes = digest.digest();
      }
    }
    // Create the backup info structure for this backup and add it to the backup
    // directory.
    // FIXME -- Should I use the date from when I started or finished?
    BackupInfo backupInfo = new BackupInfo(backupDirectory, backupID,
                                           new Date(), false, compress,
                                           encrypt, digestBytes, macBytes,
                                           null, backupProperties);
    try
    {
      backupDirectory.addBackup(backupInfo);
      backupDirectory.writeBackupDirectoryDescriptor();
    }
    catch (Exception e)
    {
      if (debugEnabled())
      {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      message = ERR_TASKS_BACKUP_CANNOT_UPDATE_BACKUP_DESCRIPTOR.get(
          backupDirectory.getDescriptorPath(), stackTraceToSingleLineString(e));
      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
                                   message, e);
    }
  }
@@ -1207,7 +1614,54 @@
                           String backupID)
         throws DirectoryException
  {
    // NYI -- Remove the backup.
    BackupInfo backupInfo = backupDirectory.getBackupInfo(backupID);
    if (backupInfo == null)
    {
      Message message = ERR_BACKUP_MISSING_BACKUPID.get(
        backupDirectory.getPath(), backupID);
      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
                                   message);
    }
    HashMap<String,String> backupProperties = backupInfo.getBackupProperties();
    String archiveFilename =
         backupProperties.get(BACKUP_PROPERTY_ARCHIVE_FILENAME);
    File archiveFile = new File(backupDirectory.getPath(), archiveFilename);
    try
    {
      backupDirectory.removeBackup(backupID);
    }
    catch (ConfigException e)
    {
      if (debugEnabled())
      {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
                                   e.getMessageObject());
    }
    try
    {
      backupDirectory.writeBackupDirectoryDescriptor();
    }
    catch (Exception e)
    {
      if (debugEnabled())
      {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      Message message = ERR_BACKUP_CANNOT_UPDATE_BACKUP_DESCRIPTOR.get(
        backupDirectory.getDescriptorPath(), stackTraceToSingleLineString(e));
      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
                                   message, e);
    }
    // Remove the archive file.
    archiveFile.delete();
  }
@@ -1231,7 +1685,316 @@
  public void restoreBackup(RestoreConfig restoreConfig)
         throws DirectoryException
  {
    // NYI -- Restore the backup.
    // First, make sure that the requested backup exists.
    BackupDirectory backupDirectory = restoreConfig.getBackupDirectory();
    String          backupPath      = backupDirectory.getPath();
    String          backupID        = restoreConfig.getBackupID();
    BackupInfo      backupInfo      = backupDirectory.getBackupInfo(backupID);
    boolean         verifyOnly      = restoreConfig.verifyOnly();
    if (backupInfo == null)
    {
      Message message =
          ERR_TASKS_RESTORE_NO_SUCH_BACKUP.get(backupID, backupPath);
      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
                                   message);
    }
    // Read the backup info structure to determine the name of the file that
    // contains the archive.  Then make sure that file exists.
    String backupFilename =
         backupInfo.getBackupProperty(BACKUP_PROPERTY_ARCHIVE_FILENAME);
    if (backupFilename == null)
    {
      Message message =
          ERR_TASKS_RESTORE_NO_BACKUP_FILE.get(backupID, backupPath);
      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
                                   message);
    }
    File backupFile = new File(backupPath + File.separator + backupFilename);
    try
    {
      if (! backupFile.exists())
      {
        Message message =
            ERR_TASKS_RESTORE_NO_SUCH_FILE.get(backupID, backupFile.getPath());
        throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
                                     message);
      }
    }
    catch (DirectoryException de)
    {
      throw de;
    }
    catch (Exception e)
    {
      Message message = ERR_TASKS_RESTORE_CANNOT_CHECK_FOR_ARCHIVE.get(
          backupID, backupFile.getPath(), stackTraceToSingleLineString(e));
      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
                                   message, e);
    }
    // If the backup is hashed, then we need to get the message digest to use
    // to verify it.
    byte[] unsignedHash = backupInfo.getUnsignedHash();
    MessageDigest digest = null;
    if (unsignedHash != null)
    {
      String digestAlgorithm =
           backupInfo.getBackupProperty(BACKUP_PROPERTY_DIGEST_ALGORITHM);
      if (digestAlgorithm == null)
      {
        Message message = ERR_TASKS_RESTORE_UNKNOWN_DIGEST.get(backupID);
        throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
                                     message);
      }
      try
      {
        digest = DirectoryServer.getCryptoManager().getMessageDigest(
                                                         digestAlgorithm);
      }
      catch (Exception e)
      {
        Message message =
            ERR_TASKS_RESTORE_CANNOT_GET_DIGEST.get(backupID, digestAlgorithm);
        throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
                                     message, e);
      }
    }
    // If the backup is signed, then we need to get the MAC to use to verify it.
    byte[] signedHash = backupInfo.getSignedHash();
    Mac mac = null;
    if (signedHash != null)
    {
      String macKeyID =
           backupInfo.getBackupProperty(BACKUP_PROPERTY_MAC_KEY_ID);
      if (macKeyID == null)
      {
        Message message = ERR_TASKS_RESTORE_UNKNOWN_MAC.get(backupID);
        throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
                                     message);
      }
      try
      {
        mac = DirectoryServer.getCryptoManager().getMacEngine(macKeyID);
      }
      catch (Exception e)
      {
        Message message = ERR_TASKS_RESTORE_CANNOT_GET_MAC.get(
            backupID, macKeyID);
        throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
                                     message, e);
      }
    }
    // Create the input stream that will be used to read the backup file.  At
    // its core, it will be a file input stream.
    InputStream inputStream;
    try
    {
      inputStream = new FileInputStream(backupFile);
    }
    catch (Exception e)
    {
      Message message = ERR_TASKS_RESTORE_CANNOT_OPEN_BACKUP_FILE.get(
          backupID, backupFile.getPath(), stackTraceToSingleLineString(e));
      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
                                   message, e);
    }
    // If the backup is encrypted, then we need to wrap the file input stream
    // in a cipher input stream.
    if (backupInfo.isEncrypted())
    {
      try
      {
        inputStream = DirectoryServer.getCryptoManager()
                                         .getCipherInputStream(inputStream);
      }
      catch (CryptoManagerException e)
      {
        Message message = ERR_TASKS_RESTORE_CANNOT_GET_CIPHER.get(
                backupFile.getPath(), stackTraceToSingleLineString(e));
        throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
                                     message, e);
      }
    }
    // Now wrap the resulting input stream in a zip stream so that we can read
    // its contents.  We don't need to worry about whether to use compression or
    // not because it will be handled automatically.
    ZipInputStream zipStream = new ZipInputStream(inputStream);
    // Read through the archive file an entry at a time.  For each entry, update
    // the digest or MAC if necessary.
    byte[] buffer = new byte[8192];
    while (true)
    {
      ZipEntry zipEntry;
      try
      {
        zipEntry = zipStream.getNextEntry();
      }
      catch (Exception e)
      {
        Message message = ERR_TASKS_RESTORE_CANNOT_GET_ZIP_ENTRY.get(
            backupID, backupFile.getPath(), stackTraceToSingleLineString(e));
        throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
                                     message, e);
      }
      if (zipEntry == null)
      {
        break;
      }
      // Get the filename for the zip entry and update the digest or MAC as
      // necessary.
      String fileName = zipEntry.getName();
      if (digest != null)
      {
        digest.update(getBytes(fileName));
      }
      if (mac != null)
      {
        mac.update(getBytes(fileName));
      }
      // If we're doing the restore, then create the output stream to write the
      // file.
      File tasksFile = getFileForPath(taskBackingFile);
      String baseDirPath = tasksFile.getParent();
      OutputStream outputStream = null;
      if (!verifyOnly)
      {
        String filePath = baseDirPath + File.separator + fileName;
        try
        {
          outputStream = new FileOutputStream(filePath);
        }
        catch (Exception e)
        {
          Message message = ERR_TASKS_RESTORE_CANNOT_CREATE_FILE.get(
              backupID, filePath, stackTraceToSingleLineString(e));
          throw new DirectoryException(
                         DirectoryServer.getServerErrorResultCode(), message,
                         e);
        }
      }
      // Read the contents of the file and update the digest or MAC as
      // necessary.
      try
      {
        while (true)
        {
          int bytesRead = zipStream.read(buffer);
          if (bytesRead < 0)
          {
            // We've reached the end of the entry.
            break;
          }
          // Update the digest or MAC if appropriate.
          if (digest != null)
          {
            digest.update(buffer, 0, bytesRead);
          }
          if (mac != null)
          {
            mac.update(buffer, 0, bytesRead);
          }
          //  Write the data to the output stream if appropriate.
          if (outputStream != null)
          {
            outputStream.write(buffer, 0, bytesRead);
          }
        }
        // We're at the end of the file so close the output stream if we're
        // writing it.
        if (outputStream != null)
        {
          outputStream.close();
        }
      }
      catch (Exception e)
      {
        Message message = ERR_TASKS_RESTORE_CANNOT_PROCESS_ARCHIVE_FILE.get(
            backupID, fileName, stackTraceToSingleLineString(e));
        throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
                                     message, e);
      }
    }
    // Close the zip stream since we don't need it anymore.
    try
    {
      zipStream.close();
    }
    catch (Exception e)
    {
      Message message = ERR_TASKS_RESTORE_ERROR_ON_ZIP_STREAM_CLOSE.get(
          backupID, backupFile.getPath(), stackTraceToSingleLineString(e));
      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
                                   message, e);
    }
    // At this point, we should be done with the contents of the ZIP file and
    // the restore should be complete.  If we were generating a digest or MAC,
    // then make sure it checks out.
    if (digest != null)
    {
      byte[] calculatedHash = digest.digest();
      if (Arrays.equals(calculatedHash, unsignedHash))
      {
        Message message = NOTE_TASKS_RESTORE_UNSIGNED_HASH_VALID.get();
        logError(message);
      }
      else
      {
        Message message =
            ERR_TASKS_RESTORE_UNSIGNED_HASH_INVALID.get(backupID);
        throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
                                     message);
      }
    }
    if (mac != null)
    {
      byte[] calculatedSignature = mac.doFinal();
      if (Arrays.equals(calculatedSignature, signedHash))
      {
        Message message = NOTE_TASKS_RESTORE_SIGNED_HASH_VALID.get();
        logError(message);
      }
      else
      {
        Message message = ERR_TASKS_RESTORE_SIGNED_HASH_INVALID.get(backupID);
        throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
                                     message);
      }
    }
    // If we are just verifying the archive, then we're done.
    if (verifyOnly)
    {
      Message message =
          NOTE_TASKS_RESTORE_VERIFY_SUCCESSFUL.get(backupID, backupPath);
      logError(message);
      return;
    }
    // If we've gotten here, then the archive was restored successfully.
    Message message = NOTE_TASKS_RESTORE_SUCCESSFUL.get(backupID, backupPath);
    logError(message);
  }
opends/src/server/org/opends/server/types/LDIFExportConfig.java
@@ -909,18 +909,18 @@
    // FIXME -- Need to add code to generate a signed hash of the LDIF
    //          content.
    try
    {
      writer.close();
    }
    catch (Exception e)
    {
      if (debugEnabled())
    if (writer != null) {
      try
      {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
        writer.close();
      }
      catch (Exception e)
      {
        if (debugEnabled())
        {
          TRACER.debugCaught(DebugLogLevel.ERROR, e);
        }
      }
    }
  }
}
opends/src/server/org/opends/server/util/ServerConstants.java
@@ -2352,6 +2352,14 @@
  /**
   * The base filename to use for the archive file containing a backup of the
   * task backend.
   */
  public static final String TASKS_BACKUP_BASE_FILENAME = "tasks-backup-";
  /**
   * The name of the directory in which lock files will be placed.
   */
  public static final String LOCKS_DIRECTORY = "locks";