/**
   * Processing recovery
   *
   * @param recoveryDTO class that contains user and tenant Information
   * @return true if the reset request is processed successfully.
   * @throws IdentityException if fails
   */
  public NotificationDataDTO recoverWithNotification(UserRecoveryDTO recoveryDTO)
      throws IdentityException {

    String notificationAddress;
    String secretKey = null;
    String confirmationKey = null;
    NotificationSendingModule module = null;
    boolean persistData = true;
    String userId = recoveryDTO.getUserId();
    String domainName = recoveryDTO.getTenantDomain();
    int tenantId = recoveryDTO.getTenantId();
    String userStore = IdentityUtil.extractDomainFromName(userId);
    String userName = UserCoreUtil.removeDomainFromName(userId);
    TenantManager tenantManager = IdentityMgtServiceComponent.getRealmService().getTenantManager();
    try {
      Tenant tenant = tenantManager.getTenant(tenantId);
      if (tenant != null) {
        domainName = tenant.getDomain();
      }

    } catch (UserStoreException e) {
      if (log.isDebugEnabled()) {
        log.debug("No Tenant domain for tenant id " + tenantId, e);
      }
    }
    NotificationDataDTO notificationData = new NotificationDataDTO();
    String internalCode = null;

    String type = recoveryDTO.getNotificationType();
    if (type != null) {
      module = modules.get(type);
    }

    if (module == null) {
      module = defaultModule;
    }

    NotificationData emailNotificationData = new NotificationData();
    String emailTemplate = null;

    notificationAddress = Utils.getEmailAddressForUser(userId, tenantId);
    String firstName =
        Utils.getClaimFromUserStoreManager(userId, tenantId, "http://wso2.org/claims/givenname");
    emailNotificationData.setTagData(FIRST_NAME, firstName);
    emailNotificationData.setTagData(USER_STORE_DOMAIN, userStore);
    emailNotificationData.setTagData(USER_NAME, userName);
    emailNotificationData.setTagData(TENANT_DOMAIN, domainName);

    if ((notificationAddress == null) || (notificationAddress.trim().length() < 0)) {
      throw new IdentityException(
          "Notification sending failure. Notification address is not defined for user : "******"Building notification with data - First name: "
              + firstName
              + " User name: "
              + userId
              + " Send To: "
              + notificationAddress);
    }

    Config config = null;
    ConfigBuilder configBuilder = ConfigBuilder.getInstance();
    try {
      config = configBuilder.loadConfiguration(ConfigType.EMAIL, StorageType.REGISTRY, tenantId);
    } catch (Exception e1) {
      throw new IdentityException("Error while loading email templates for user : "******"Error while getting user's external code string.", e);
        }
        secretKey = UUIDGenerator.generateUUID();
        emailNotificationData.setTagData(CONFIRMATION_CODE, confirmationKey);
        emailTemplate =
            config.getProperty(IdentityMgtConstants.Notification.PASSWORD_RESET_RECOVERY);

      } else if (IdentityMgtConstants.Notification.ACCOUNT_CONFORM.equals(notification)) {
        confirmationKey = UUIDGenerator.generateUUID();
        secretKey = UUIDGenerator.generateUUID();
        emailNotificationData.setTagData(CONFIRMATION_CODE, confirmationKey);
        emailTemplate = config.getProperty(IdentityMgtConstants.Notification.ACCOUNT_CONFORM);

      } else if (IdentityMgtConstants.Notification.TEMPORARY_PASSWORD.equals(notification)) {
        String temporaryPassword = recoveryDTO.getTemporaryPassword(); // TODO
        if (temporaryPassword == null || temporaryPassword.trim().length() < 1) {
          char[] chars = IdentityMgtConfig.getInstance().getPasswordGenerator().generatePassword();
          temporaryPassword = new String(chars);
        }
        Utils.updatePassword(userId, tenantId, temporaryPassword);
        emailNotificationData.setTagData(TEMPORARY_PASSWORD, temporaryPassword);
        emailTemplate = config.getProperty(IdentityMgtConstants.Notification.TEMPORARY_PASSWORD);
        persistData = false;
      } else if (IdentityMgtConstants.Notification.ACCOUNT_UNLOCK.equals(notification)) {
        emailTemplate = config.getProperty(IdentityMgtConstants.Notification.ACCOUNT_UNLOCK);
        persistData = false;
      } else if (IdentityMgtConstants.Notification.ACCOUNT_ID_RECOVERY.equals(notification)) {
        emailTemplate = config.getProperty(IdentityMgtConstants.Notification.ACCOUNT_ID_RECOVERY);
        persistData = false;
      } else if (IdentityMgtConstants.Notification.ASK_PASSWORD.equals(notification)) {
        if (firstName == null || firstName.isEmpty()) {
          emailNotificationData.setTagData(FIRST_NAME, userId);
        }
        internalCode = generateUserCode(2, userId);
        try {
          confirmationKey = getUserExternalCodeStr(internalCode);
        } catch (Exception e) {
          throw new IdentityException("Error while with recovering with password.", e);
        }
        secretKey = UUIDGenerator.generateUUID();
        emailNotificationData.setTagData(CONFIRMATION_CODE, confirmationKey);
        emailTemplate = config.getProperty(IdentityMgtConstants.Notification.ASK_PASSWORD);
      }

      if (log.isDebugEnabled()) {
        log.debug("Notification type: " + notification);
      }
    }

    Notification emailNotification = null;
    try {
      emailNotification =
          NotificationBuilder.createNotification("EMAIL", emailTemplate, emailNotificationData);
    } catch (Exception e) {
      throw new IdentityException("Error when creating notification for user : " + userId, e);
    }

    notificationData.setNotificationAddress(notificationAddress);
    notificationData.setUserId(userId);
    notificationData.setDomainName(domainName);
    notificationData.setNotificationType(recoveryDTO.getNotificationType());

    if (persistData) {
      UserRecoveryDataDO recoveryDataDO =
          new UserRecoveryDataDO(userId, tenantId, internalCode, secretKey);
      dataStore.invalidate(userId, tenantId);
      dataStore.store(recoveryDataDO);
    }

    if (IdentityMgtConfig.getInstance().isNotificationInternallyManaged()) {
      module.setNotificationData(notificationData);
      module.setNotification(emailNotification);
      notificationSender.sendNotification(module);
      notificationData.setNotificationSent(true);
    } else {
      notificationData.setNotificationSent(false);
      notificationData.setNotificationCode(confirmationKey);
    }

    return notificationData;
  }
  /**
   * This method is used to update the password in the system for password recovery process. Before
   * calling this method caller needs to call verifyConfirmationCode and get the newly generated
   * confirmation code.
   *
   * @param username - username
   * @param confirmationCode - newly generated confirmation code
   * @param newPassword - new password
   * @return - VerificationBean with operation status true or false.
   * @throws IdentityMgtServiceException
   */
  public VerificationBean updatePassword(
      String username, String confirmationCode, String newPassword)
      throws IdentityMgtServiceException {

    RecoveryProcessor recoveryProcessor = IdentityMgtServiceComponent.getRecoveryProcessor();
    VerificationBean bean = null;

    if (log.isDebugEnabled()) {
      log.debug("User update password request received with username: "******"No Tenant id for tenant domain " + userDTO.getTenantDomain(), e);
      }

      if (recoveryProcessor
          .verifyConfirmationCode(3, userDTO.getUserId(), confirmationCode)
          .isVerified()) {
        Utils.updatePassword(userDTO.getUserId(), tenantId, newPassword);
        log.info(
            "Credential is updated for user : "******" and tenant domain : "
                + userDTO.getTenantDomain());
        IdentityMgtConfig.getInstance()
            .getRecoveryDataStore()
            .invalidate(userDTO.getUserId(), tenantId);
        bean = new VerificationBean(true);
      } else {
        String msg =
            "Invalid user tried to update credential with user Id : "
                + userDTO.getUserId()
                + " and tenant domain : "
                + userDTO.getTenantDomain();
        bean = new VerificationBean(VerificationBean.ERROR_CODE_INVALID_USER + " " + msg);
        bean.setVerified(false);
        log.error(msg);
      }

    } catch (Exception e) {
      bean =
          handleError(
              VerificationBean.ERROR_CODE_UNEXPECTED
                  + " Error while updating credential for user: "
                  + username,
              e);
      return bean;
    } finally {
      if (IdentityMgtConfig.getInstance().isSaasEnabled()) {
        PrivilegedCarbonContext.endTenantFlow();
      }
    }
    return bean;
  }