/**
   * Generates an entry for a backup directory based on the provided DN. The DN must contain an RDN
   * component that specifies the path to the backup directory, and that directory must exist and be
   * a valid backup directory.
   *
   * @param entryDN The DN of the backup directory entry to retrieve.
   * @return The requested backup directory entry.
   * @throws DirectoryException If the specified directory does not exist or is not a valid backup
   *     directory, or if the DN does not specify any backup directory.
   */
  private Entry getBackupDirectoryEntry(DN entryDN) throws DirectoryException {
    // Make sure that the DN specifies a backup directory.
    AttributeType t = DirectoryServer.getAttributeType(ATTR_BACKUP_DIRECTORY_PATH, true);
    AttributeValue v = entryDN.getRDN().getAttributeValue(t);
    if (v == null) {
      Message message = ERR_BACKUP_DN_DOES_NOT_SPECIFY_DIRECTORY.get(String.valueOf(entryDN));
      throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message, backupBaseDN, null);
    }

    // Get a handle to the backup directory and the information that it
    // contains.
    BackupDirectory backupDirectory;
    try {
      backupDirectory = BackupDirectory.readBackupDirectoryDescriptor(v.getValue().toString());
    } catch (ConfigException ce) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, ce);
      }

      Message message =
          ERR_BACKUP_INVALID_BACKUP_DIRECTORY.get(String.valueOf(entryDN), ce.getMessage());
      throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message);
    } catch (Exception e) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }

      Message message = ERR_BACKUP_ERROR_GETTING_BACKUP_DIRECTORY.get(getExceptionMessage(e));
      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), message);
    }

    // Construct the backup directory entry to return.
    LinkedHashMap<ObjectClass, String> ocMap = new LinkedHashMap<ObjectClass, String>(2);
    ocMap.put(DirectoryServer.getTopObjectClass(), OC_TOP);

    ObjectClass backupDirOC = DirectoryServer.getObjectClass(OC_BACKUP_DIRECTORY, true);
    ocMap.put(backupDirOC, OC_BACKUP_DIRECTORY);

    LinkedHashMap<AttributeType, List<Attribute>> opAttrs =
        new LinkedHashMap<AttributeType, List<Attribute>>(0);
    LinkedHashMap<AttributeType, List<Attribute>> userAttrs =
        new LinkedHashMap<AttributeType, List<Attribute>>(3);

    ArrayList<Attribute> attrList = new ArrayList<Attribute>(1);
    attrList.add(Attributes.create(t, v));
    userAttrs.put(t, attrList);

    t = DirectoryServer.getAttributeType(ATTR_BACKUP_BACKEND_DN, true);
    attrList = new ArrayList<Attribute>(1);
    attrList.add(
        Attributes.create(
            t, AttributeValues.create(t, backupDirectory.getConfigEntryDN().toString())));
    userAttrs.put(t, attrList);

    Entry e = new Entry(entryDN, ocMap, userAttrs, opAttrs);
    e.processVirtualAttributes();
    return e;
  }
  /**
   * Generates an entry for a backup based on the provided DN. The DN must have an RDN component
   * that specifies the backup ID, and the parent DN must have an RDN component that specifies the
   * backup directory.
   *
   * @param entryDN The DN of the backup entry to retrieve.
   * @return The requested backup entry.
   * @throws DirectoryException If the specified backup does not exist or is invalid.
   */
  private Entry getBackupEntry(DN entryDN) throws DirectoryException {
    // First, get the backup ID from the entry DN.
    AttributeType idType = DirectoryServer.getAttributeType(ATTR_BACKUP_ID, true);
    AttributeValue idValue = entryDN.getRDN().getAttributeValue(idType);
    if (idValue == null) {
      Message message = ERR_BACKUP_NO_BACKUP_ID_IN_DN.get(String.valueOf(entryDN));
      throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message);
    }
    String backupID = idValue.getValue().toString();

    // Next, get the backup directory from the parent DN.
    DN parentDN = entryDN.getParentDNInSuffix();
    if (parentDN == null) {
      Message message = ERR_BACKUP_NO_BACKUP_PARENT_DN.get(String.valueOf(entryDN));
      throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message);
    }

    AttributeType t = DirectoryServer.getAttributeType(ATTR_BACKUP_DIRECTORY_PATH, true);
    AttributeValue v = parentDN.getRDN().getAttributeValue(t);
    if (v == null) {
      Message message = ERR_BACKUP_NO_BACKUP_DIR_IN_DN.get(String.valueOf(entryDN));
      throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message);
    }

    BackupDirectory backupDirectory;
    try {
      backupDirectory = BackupDirectory.readBackupDirectoryDescriptor(v.getValue().toString());
    } catch (ConfigException ce) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, ce);
      }

      Message message =
          ERR_BACKUP_INVALID_BACKUP_DIRECTORY.get(String.valueOf(entryDN), ce.getMessageObject());
      throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message);
    } catch (Exception e) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }

      Message message = ERR_BACKUP_ERROR_GETTING_BACKUP_DIRECTORY.get(getExceptionMessage(e));
      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), message);
    }

    BackupInfo backupInfo = backupDirectory.getBackupInfo(backupID);
    if (backupInfo == null) {
      Message message = ERR_BACKUP_NO_SUCH_BACKUP.get(backupID, backupDirectory.getPath());
      throw new DirectoryException(ResultCode.NO_SUCH_OBJECT, message, parentDN, null);
    }

    // Construct the backup entry to return.
    LinkedHashMap<ObjectClass, String> ocMap = new LinkedHashMap<ObjectClass, String>(3);
    ocMap.put(DirectoryServer.getTopObjectClass(), OC_TOP);

    ObjectClass oc = DirectoryServer.getObjectClass(OC_BACKUP_INFO, true);
    ocMap.put(oc, OC_BACKUP_INFO);

    oc = DirectoryServer.getObjectClass(OC_EXTENSIBLE_OBJECT_LC, true);
    ocMap.put(oc, OC_EXTENSIBLE_OBJECT);

    LinkedHashMap<AttributeType, List<Attribute>> opAttrs =
        new LinkedHashMap<AttributeType, List<Attribute>>(0);
    LinkedHashMap<AttributeType, List<Attribute>> userAttrs =
        new LinkedHashMap<AttributeType, List<Attribute>>();

    ArrayList<Attribute> attrList = new ArrayList<Attribute>(1);
    attrList.add(Attributes.create(idType, idValue));
    userAttrs.put(idType, attrList);

    backupInfo.getBackupDirectory();
    attrList = new ArrayList<Attribute>(1);
    attrList.add(Attributes.create(t, v));
    userAttrs.put(t, attrList);

    Date backupDate = backupInfo.getBackupDate();
    if (backupDate != null) {
      t = DirectoryServer.getAttributeType(ATTR_BACKUP_DATE, true);
      attrList = new ArrayList<Attribute>(1);
      attrList.add(
          Attributes.create(
              t, AttributeValues.create(t, GeneralizedTimeSyntax.format(backupDate))));
      userAttrs.put(t, attrList);
    }

    t = DirectoryServer.getAttributeType(ATTR_BACKUP_COMPRESSED, true);
    attrList = new ArrayList<Attribute>(1);
    attrList.add(Attributes.create(t, BooleanSyntax.createBooleanValue(backupInfo.isCompressed())));
    userAttrs.put(t, attrList);

    t = DirectoryServer.getAttributeType(ATTR_BACKUP_ENCRYPTED, true);
    attrList = new ArrayList<Attribute>(1);
    attrList.add(Attributes.create(t, BooleanSyntax.createBooleanValue(backupInfo.isEncrypted())));
    userAttrs.put(t, attrList);

    t = DirectoryServer.getAttributeType(ATTR_BACKUP_INCREMENTAL, true);
    attrList = new ArrayList<Attribute>(1);
    attrList.add(
        Attributes.create(t, BooleanSyntax.createBooleanValue(backupInfo.isIncremental())));
    userAttrs.put(t, attrList);

    HashSet<String> dependencies = backupInfo.getDependencies();
    if (dependencies != null && !dependencies.isEmpty()) {
      t = DirectoryServer.getAttributeType(ATTR_BACKUP_DEPENDENCY, true);
      AttributeBuilder builder = new AttributeBuilder(t);
      for (String s : dependencies) {
        builder.add(AttributeValues.create(t, s));
      }
      attrList = new ArrayList<Attribute>(1);
      attrList.add(builder.toAttribute());
      userAttrs.put(t, attrList);
    }

    byte[] signedHash = backupInfo.getSignedHash();
    if (signedHash != null) {
      t = DirectoryServer.getAttributeType(ATTR_BACKUP_SIGNED_HASH, true);
      attrList = new ArrayList<Attribute>(1);
      attrList.add(Attributes.create(t, AttributeValues.create(t, ByteString.wrap(signedHash))));
      userAttrs.put(t, attrList);
    }

    byte[] unsignedHash = backupInfo.getUnsignedHash();
    if (unsignedHash != null) {
      t = DirectoryServer.getAttributeType(ATTR_BACKUP_UNSIGNED_HASH, true);
      attrList = new ArrayList<Attribute>(1);
      attrList.add(Attributes.create(t, AttributeValues.create(t, ByteString.wrap(unsignedHash))));
      userAttrs.put(t, attrList);
    }

    HashMap<String, String> properties = backupInfo.getBackupProperties();
    if (properties != null && !properties.isEmpty()) {
      for (Map.Entry<String, String> e : properties.entrySet()) {
        t = DirectoryServer.getAttributeType(toLowerCase(e.getKey()), true);
        attrList = new ArrayList<Attribute>(1);
        attrList.add(Attributes.create(t, AttributeValues.create(t, e.getValue())));
        userAttrs.put(t, attrList);
      }
    }

    Entry e = new Entry(entryDN, ocMap, userAttrs, opAttrs);
    e.processVirtualAttributes();
    return e;
  }