/*
 * Copyright (c) 2025, WSO2 LLC. (http://www.wso2.com).
 *
 * WSO2 LLC. licenses this file to you under the Apache License,
 * Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.wso2.carbon.is.migration.service.v710.migrator;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.wso2.carbon.context.CarbonContext;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.identity.base.IdentityRuntimeException;
import org.wso2.carbon.identity.core.IdentityRegistryResources;
import org.wso2.carbon.identity.core.migrate.MigrationClientException;
import org.wso2.carbon.identity.core.model.SAMLSSOServiceProviderDO;
import org.wso2.carbon.identity.core.persistence.registry.RegistryResourceMgtService;
import org.wso2.carbon.identity.core.persistence.registry.RegistryResourceMgtServiceImpl;
import org.wso2.carbon.identity.core.util.IdentityTenantUtil;
import org.wso2.carbon.is.migration.service.Migrator;
import org.wso2.carbon.is.migration.service.v710.dao.SAMLDAO;
import org.wso2.carbon.is.migration.util.Utility;
import org.wso2.carbon.registry.core.Collection;
import org.wso2.carbon.registry.core.Resource;
import org.wso2.carbon.registry.core.exceptions.RegistryException;
import org.wso2.carbon.user.api.Tenant;

import java.sql.SQLTransientException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Properties;
import java.util.Set;

import static org.wso2.carbon.base.MultitenantConstants.SUPER_TENANT_DOMAIN_NAME;
import static org.wso2.carbon.base.MultitenantConstants.SUPER_TENANT_ID;
import static org.wso2.carbon.is.migration.service.v710.constants.SAMLRegistryConstants.SAML_SSO_BASE_PATH;

/**
 * Migration implementation to migrate SAML SSO configs.
 */
public class SAMLMigrator extends Migrator {

    private static final Logger LOG = LoggerFactory.getLogger(SAMLMigrator.class);
    private static final String WAIT_TIME = "waitTime";
    private static final String ROLLBACK_ALLOWED = "rollbackAllowed";
    private static final String SKIP_SUPER_TENANT = "skipSuperTenant";
    private static final String HAS_MIGRATED = "hasMigrated";
    private static final long DEFAULT_WAIT_TIME_IN_MILLIS = 500;

    private final SAMLDAO samlDAO = new SAMLDAO();
    private final RegistryResourceMgtService resourceMgtService = new RegistryResourceMgtServiceImpl();

    private long waitTimeInMillis = DEFAULT_WAIT_TIME_IN_MILLIS;
    private boolean isRollbackAllowed = false;
    private boolean skipSuperTenant = false;

    @Override
    public void dryRun() throws MigrationClientException {

        LOG.info("DM-SAML-DR>> Data migration (dry run) of SAML service providers started.");
        migrateSAMLServiceProviders(true);
    }

    @Override
    public void migrate() throws MigrationClientException {

        LOG.info("DM-SAML>> Data migration of  SAML service providers started.");
        migrateSAMLServiceProviders(false);
    }

    private void migrateSAMLServiceProviders(boolean isDryRun) throws MigrationClientException {

        Properties migrationProperties = getMigratorConfig().getParameters();

        if (migrationProperties.containsKey(WAIT_TIME)) {
            waitTimeInMillis = (int) migrationProperties.get(WAIT_TIME);
        }
        LOG.info("DM-SAML>> Parameters: Wait time {}ms.", waitTimeInMillis);

        if (migrationProperties.containsKey(ROLLBACK_ALLOWED)) {
            String rollback = (String) migrationProperties.get(ROLLBACK_ALLOWED);

            if (StringUtils.isNotBlank(rollback) && Boolean.parseBoolean(rollback)) {
                isRollbackAllowed = true;
            }
        }
        LOG.info("DM-SAML>> Parameters: isRollbackAllowed: {}.", isRollbackAllowed);

        if (migrationProperties.containsKey(SKIP_SUPER_TENANT)) {
            String skipSuperTenant = (String) migrationProperties.get(SKIP_SUPER_TENANT);

            if (StringUtils.isNotBlank(skipSuperTenant) && Boolean.parseBoolean(skipSuperTenant)) {
                this.skipSuperTenant = true;
            }
        }
        LOG.info("DM-SAML>> Parameters: skipSuperTenant: {}.", skipSuperTenant);

        int successTenantCount = 0;
        int errorTenantCount = 0;
        int inactiveTenantCount = 0;

        Set<Tenant> tenants = getTenants();

        int totalTenantCount = tenants.size();
        LOG.info("DM-SAML>> Found {} tenants in the system.",
                skipSuperTenant ? totalTenantCount : totalTenantCount + 1); // Including super tenant.

        try {
            // Migrate super tenant.
            if (!skipSuperTenant) {
                migrateForTenant(isDryRun, false, SUPER_TENANT_ID, SUPER_TENANT_DOMAIN_NAME);
                successTenantCount++;
            } else {
                LOG.info("DM-SAML>> Skipping super tenant from the migration.");
            }

            // Migrate other tenants.
            boolean ignoreForInactiveTenants = isIgnoreForInactiveTenants();
            if (ignoreForInactiveTenants) {
                tenants = Utility.getActiveTenants(tenants);
                inactiveTenantCount = totalTenantCount - tenants.size();
                LOG.info("DM-SAML>> Excluding {} inactive tenants from the migration.", inactiveTenantCount);
            }
            totalTenantCount = tenants.size();
            if (!skipSuperTenant) {
                totalTenantCount++; // Include super tenant.
            }
            LOG.info("DM-SAML>> Selected {} tenants for the migration.", totalTenantCount);

            List<Tenant> tenantList = new ArrayList<>(tenants);
            tenantList.sort(Comparator.comparingInt(Tenant::getId));

            int i = 0;
            for (Tenant tenant : tenantList) {
                i++;
                int tenantId = tenant.getId();
                String tenantDomain = tenant.getDomain();

                LOG.info("DM-SAML>> Starting migration for {} of {} tenant.", i, totalTenantCount);
                LOG.info("DM-SAML>> Migrating tenant: {} with tid: {}.", tenantDomain, tenantId);

                try {
                    PrivilegedCarbonContext.startTenantFlow();
                    PrivilegedCarbonContext carbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext();
                    carbonContext.setTenantId(tenantId);
                    carbonContext.setTenantDomain(tenantDomain);
                    migrateForTenant(isDryRun, false, tenantId, tenantDomain);
                    successTenantCount++;
                } catch (MigrationClientException e) {
                    if (!isContinueOnError()) {
                        throw new MigrationClientException(e.getMessage(), e);
                    }
                    errorTenantCount++;
                    LOG.error("DM-SAML>> Error while migrating SAML service providers in tenant {}.", tenantDomain, e);
                } finally {
                    PrivilegedCarbonContext.endTenantFlow();
                }
                LOG.info("DM-SAML>> SAML service provider migration successfully completed for tenant {}.",
                        tenantDomain);
            }
        } catch (MigrationClientException e) {
            errorTenantCount++;
            LOG.error("DM-SAML>> Error while migrating SAML service providers.", e);
        }

        if (errorTenantCount == 0) {
            LOG.info("DM-SAML>> SAML service providers data migration successfully completed.");
        } else {
            LOG.info("DM-SAML>> SAML service providers data migration completed with errors in {} tenants.",
                    errorTenantCount);
        }
        LOG.info("DM-SAML>> Successfully migrated: {} of {} tenants.", successTenantCount, totalTenantCount);
        LOG.info("DM-SAML>> Found issues with:  {} of {} tenants.", errorTenantCount, totalTenantCount);
        LOG.info("DM-SAML>> Skipped {} inactive tenants.", inactiveTenantCount);
    }

    private void migrateForTenant(boolean isDryRun, boolean isRetry, int tenantId, String tenantDomain)
            throws MigrationClientException {

        try {
            if (tenantId != SUPER_TENANT_ID) {
                IdentityTenantUtil.getTenantRegistryLoader().loadTenantRegistry(tenantId);
            }
            migrateSAMLServiceProviders(isDryRun, tenantDomain);
        } catch (RegistryException e) {
            // This is ideally needed to be handled by each respective components.
            // Since carbon components doesn't handle transient exceptions across the board, we need to handle it here.
            if (!isRetry && isTransientException(e)) {
                LOG.error("DM-SAML>> Transient error occurred while migrating SAML service providers in tenant {}. ",
                        tenantDomain, e);
                try {
                    LOG.info("DM-SAML>> Retrying after waiting for 2 minutes.");
                    Thread.sleep(120 * 1000L);
                } catch (InterruptedException ex) {
                    LOG.error("DM-SAML>> Retrying without waiting.", ex);
                }
                migrateForTenant(isDryRun, true, tenantId, tenantDomain);
            } else {
                throw new MigrationClientException("Error while migrating tenant: " + tenantDomain, e);
            }
        }
    }

    private void migrateSAMLServiceProviders(boolean isDryRun, String tenantDomain) throws MigrationClientException {

        Resource resource;
        try {
            resource = resourceMgtService.getIdentityResource(SAML_SSO_BASE_PATH, tenantDomain);
            if (resource == null) {
                LOG.info("DM-SAML>> No SAML service providers found in tenant {}.", tenantDomain);
                return;
            }

        } catch (IdentityRuntimeException e) {
            String msg = String.format("Error while checking the existence of SAML service providers in tenant %s.",
                    tenantDomain);
            throw new MigrationClientException(msg, e);
        }

        LOG.info("DM-SAML>> Listing SAML service providers in tenant {}.", tenantDomain);

        List<SAMLSSOServiceProviderDO> samlServiceProviders =
                getServiceProvidersFromRegistry(SAML_SSO_BASE_PATH, tenantDomain);

        if (samlServiceProviders.isEmpty()) {
            LOG.info("DM-SAML>> No SAML service providers found in tenant {}.", tenantDomain);
            return;
        }
        LOG.info("DM-SAML>> Found {} SAML service providers in Registry in tenant {}.", samlServiceProviders.size(),
                tenantDomain);

        try {
            int tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId();

            samlDAO.migrateSAMLServiceProviders(samlServiceProviders, isDryRun, tenantId);
            LOG.info("DM-SAML>> SAML service providers successfully migrated in tenant {}.", tenantDomain);

            try {
                LOG.info("DM-SAML>> Cleaning SAML service providers in registry in tenant {}.", tenantDomain);
                if (isDryRun) {
                    LOG.info(
                            "DM-SAML>> SAML service providers in registry in tenant {} deletion will be skipped due to dry run.",
                            tenantDomain);
                } else if (isRollbackAllowed) {
                    resource.addProperty(HAS_MIGRATED, Boolean.TRUE.toString());
                    resourceMgtService.putIdentityResource(resource, SAML_SSO_BASE_PATH, tenantDomain);
                    LOG.info(
                            "DM-SAML>> SAML service providers in registry in tenant {} deletion will be skipped allowing room " +
                                    "to rollback.", tenantDomain);
                } else {
                    resourceMgtService.deleteIdentityResource(SAML_SSO_BASE_PATH, tenantDomain);
                    LOG.info("DM-SAML>> SAML service providers in registry successfully deleted for tenant {}.",
                            tenantDomain);
                }
                LOG.info("DM-SAML>> SAML service providers migration in tenant {} successfully completed.",
                        tenantDomain);
            } catch (IdentityRuntimeException e) {
                String msg = String.format("Error while cleaning SAML service providers in tenant %s.", tenantDomain);
                throw new MigrationClientException(msg, e);
            }
        } finally {
            if (waitTimeInMillis > 0) {
                try {
                    LOG.info("DM-SAML>> Waiting {}ms to cool down...", waitTimeInMillis);
                    Thread.sleep(waitTimeInMillis);
                } catch (InterruptedException e) {
                    LOG.error("SAML-DM>> Error while waiting for the next batch.", e);
                }
            }
        }
    }

    private List<SAMLSSOServiceProviderDO> getServiceProvidersFromRegistry(String path, String tenantDomain)
            throws MigrationClientException {

        try {
            Resource samlSSOServiceProvidersResource = resourceMgtService.getIdentityResource(path, tenantDomain);
            if (!(samlSSOServiceProvidersResource instanceof Collection)) {
                String message = String.format(
                        "Invalid registry resource found while trying to list SAML service providers in tenant %s.",
                        tenantDomain);
                throw new MigrationClientException(message);
            }

            Collection samlSSOServiceProvidersCollection = (Collection) samlSSOServiceProvidersResource;
            List<SAMLSSOServiceProviderDO> samlSSOServiceProviderDOS = new ArrayList<>();
            for (String resource : samlSSOServiceProvidersCollection.getChildren()) {
                Resource SAMLResource = resourceMgtService.getIdentityResource(resource, tenantDomain);
                samlSSOServiceProviderDOS.add(getSAMLSSOServiceProviderDO(SAMLResource));
            }
            return samlSSOServiceProviderDOS;
        } catch (RegistryException | IdentityRuntimeException e) {
            String errorMessage =
                    String.format("Error while listing SAML service providers in tenant %s.", tenantDomain);
            throw new MigrationClientException(errorMessage, e);
        }
    }

    private SAMLSSOServiceProviderDO getSAMLSSOServiceProviderDO(Resource resource) {

        SAMLSSOServiceProviderDO serviceProviderDO = new SAMLSSOServiceProviderDO();
        serviceProviderDO.setIssuer(resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_ISSUER));
        serviceProviderDO.setAssertionConsumerUrls(
                resource.getPropertyValues(IdentityRegistryResources.PROP_SAML_SSO_ASSERTION_CONS_URLS));
        serviceProviderDO.setDefaultAssertionConsumerUrl(
                resource.getProperty(IdentityRegistryResources.PROP_DEFAULT_SAML_SSO_ASSERTION_CONS_URL));
        serviceProviderDO.setCertAlias(resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_ISSUER_CERT_ALIAS));

        if (StringUtils.isNotEmpty(resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_SIGNING_ALGORITHM))) {
            serviceProviderDO.setSigningAlgorithmUri(
                    resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_SIGNING_ALGORITHM));
        }

        if (resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_ASSERTION_QUERY_REQUEST_PROFILE_ENABLED) !=
                null) {
            serviceProviderDO.setAssertionQueryRequestProfileEnabled(Boolean.valueOf(resource.getProperty(
                    IdentityRegistryResources.PROP_SAML_SSO_ASSERTION_QUERY_REQUEST_PROFILE_ENABLED).trim()));
        }

        if (resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_SUPPORTED_ASSERTION_QUERY_REQUEST_TYPES) !=
                null) {
            serviceProviderDO.setSupportedAssertionQueryRequestTypes(resource.getProperty(
                    IdentityRegistryResources.PROP_SAML_SSO_SUPPORTED_ASSERTION_QUERY_REQUEST_TYPES).trim());
        }

        if (resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_ENABLE_SAML2_ARTIFACT_BINDING) != null) {
            serviceProviderDO.setEnableSAML2ArtifactBinding(Boolean.valueOf(
                    resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_ENABLE_SAML2_ARTIFACT_BINDING)
                            .trim()));
        }

        if (StringUtils.isNotEmpty(resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_DIGEST_ALGORITHM))) {
            serviceProviderDO.setDigestAlgorithmUri(
                    resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_DIGEST_ALGORITHM));
        }

        if (StringUtils.isNotEmpty(
                resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_ASSERTION_ENCRYPTION_ALGORITHM))) {
            serviceProviderDO.setAssertionEncryptionAlgorithmUri(
                    resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_ASSERTION_ENCRYPTION_ALGORITHM));
        }

        if (StringUtils.isNotEmpty(
                resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_KEY_ENCRYPTION_ALGORITHM))) {
            serviceProviderDO.setKeyEncryptionAlgorithmUri(
                    resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_KEY_ENCRYPTION_ALGORITHM));
        }

        if (resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_DO_SINGLE_LOGOUT) != null) {
            serviceProviderDO.setDoSingleLogout(Boolean.valueOf(
                    resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_DO_SINGLE_LOGOUT).trim()));
        }

        if (resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_NAMEID_FORMAT) != null) {
            serviceProviderDO.setNameIDFormat(
                    resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_NAMEID_FORMAT));
        }

        if (resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_ENABLE_NAMEID_CLAIMURI) != null) {
            if (Boolean.valueOf(
                    resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_ENABLE_NAMEID_CLAIMURI).trim())) {
                serviceProviderDO.setNameIdClaimUri(
                        resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_NAMEID_CLAIMURI));
            }
        }

        serviceProviderDO.setLoginPageURL(resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_LOGIN_PAGE_URL));

        if (resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_DO_SIGN_RESPONSE) != null) {
            serviceProviderDO.setDoSignResponse(Boolean.valueOf(
                    resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_DO_SIGN_RESPONSE).trim()));
        }

        if (serviceProviderDO.isDoSingleLogout()) {
            serviceProviderDO.setSloResponseURL(
                    resource.getProperty(IdentityRegistryResources.PROP_SAML_SLO_RESPONSE_URL));
            serviceProviderDO.setSloRequestURL(
                    resource.getProperty(IdentityRegistryResources.PROP_SAML_SLO_REQUEST_URL));
            // Check front channel logout enable.
            if (resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_DO_FRONT_CHANNEL_LOGOUT) != null) {
                serviceProviderDO.setDoFrontChannelLogout(Boolean.valueOf(
                        resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_DO_FRONT_CHANNEL_LOGOUT).trim()));
                if (serviceProviderDO.isDoFrontChannelLogout()) {
                    if (resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_FRONT_CHANNEL_LOGOUT_BINDING) !=
                            null) {
                        serviceProviderDO.setFrontChannelLogoutBinding(resource.getProperty(
                                IdentityRegistryResources.PROP_SAML_SSO_FRONT_CHANNEL_LOGOUT_BINDING));
                    } else {
                        // Default is redirect-binding.
                        serviceProviderDO.setFrontChannelLogoutBinding(
                                IdentityRegistryResources.DEFAULT_FRONT_CHANNEL_LOGOUT_BINDING);
                    }
                }
            }
        }

        if (resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_DO_SIGN_ASSERTIONS) != null) {
            serviceProviderDO.setDoSignAssertions(Boolean.valueOf(
                    resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_DO_SIGN_ASSERTIONS).trim()));
        }

        if (resource.getProperty(IdentityRegistryResources.PROP_SAML_ENABLE_ECP) != null) {
            serviceProviderDO.setSamlECP(
                    Boolean.valueOf(resource.getProperty(IdentityRegistryResources.PROP_SAML_ENABLE_ECP).trim()));
        }

        if (resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_ATTRIB_CONSUMING_SERVICE_INDEX) != null) {
            serviceProviderDO.setAttributeConsumingServiceIndex(
                    resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_ATTRIB_CONSUMING_SERVICE_INDEX));
        } else {
            // Specific DB's (like oracle) returns empty strings as null.
            serviceProviderDO.setAttributeConsumingServiceIndex("");
        }

        if (resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_REQUESTED_CLAIMS) != null) {
            serviceProviderDO.setRequestedClaims(
                    resource.getPropertyValues(IdentityRegistryResources.PROP_SAML_SSO_REQUESTED_CLAIMS));
        }

        if (resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_REQUESTED_AUDIENCES) != null) {
            serviceProviderDO.setRequestedAudiences(
                    resource.getPropertyValues(IdentityRegistryResources.PROP_SAML_SSO_REQUESTED_AUDIENCES));
        }

        if (resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_REQUESTED_RECIPIENTS) != null) {
            serviceProviderDO.setRequestedRecipients(
                    resource.getPropertyValues(IdentityRegistryResources.PROP_SAML_SSO_REQUESTED_RECIPIENTS));
        }

        if (resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_ENABLE_ATTRIBUTES_BY_DEFAULT) != null) {
            String enableAttrByDefault =
                    resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_ENABLE_ATTRIBUTES_BY_DEFAULT);
            serviceProviderDO.setEnableAttributesByDefault(Boolean.valueOf(enableAttrByDefault));
        }
        if (resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_IDP_INIT_SSO_ENABLED) != null) {
            serviceProviderDO.setIdPInitSSOEnabled(Boolean.valueOf(
                    resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_IDP_INIT_SSO_ENABLED).trim()));
        }
        if (resource.getProperty(IdentityRegistryResources.PROP_SAML_SLO_IDP_INIT_SLO_ENABLED) != null) {
            serviceProviderDO.setIdPInitSLOEnabled(Boolean.valueOf(
                    resource.getProperty(IdentityRegistryResources.PROP_SAML_SLO_IDP_INIT_SLO_ENABLED).trim()));
            if (serviceProviderDO.isIdPInitSLOEnabled() &&
                    resource.getProperty(IdentityRegistryResources.PROP_SAML_IDP_INIT_SLO_RETURN_URLS) != null) {
                serviceProviderDO.setIdpInitSLOReturnToURLs(
                        resource.getPropertyValues(IdentityRegistryResources.PROP_SAML_IDP_INIT_SLO_RETURN_URLS));
            }
        }
        if (resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_ENABLE_ENCRYPTED_ASSERTION) != null) {
            serviceProviderDO.setDoEnableEncryptedAssertion(Boolean.valueOf(
                    resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_ENABLE_ENCRYPTED_ASSERTION).trim()));
        }
        if (resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_VALIDATE_SIGNATURE_IN_REQUESTS) != null) {
            serviceProviderDO.setDoValidateSignatureInRequests(Boolean.valueOf(
                    resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_VALIDATE_SIGNATURE_IN_REQUESTS)
                            .trim()));
        }
        if (resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_VALIDATE_SIGNATURE_IN_ARTIFACT_RESOLVE) !=
                null) {
            serviceProviderDO.setDoValidateSignatureInArtifactResolve(Boolean.valueOf(
                    resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_VALIDATE_SIGNATURE_IN_ARTIFACT_RESOLVE)
                            .trim()));
        }
        if (resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_ISSUER_QUALIFIER) != null) {
            serviceProviderDO.setIssuerQualifier(
                    resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_ISSUER_QUALIFIER));
        }
        if (resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_IDP_ENTITY_ID_ALIAS) != null) {
            serviceProviderDO.setIdpEntityIDAlias(
                    resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_IDP_ENTITY_ID_ALIAS));
        }
        if (resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_ATTRIBUTE_NAME_FORMAT) != null) {
            serviceProviderDO.setAttributeNameFormat(
                    resource.getProperty(IdentityRegistryResources.PROP_SAML_SSO_ATTRIBUTE_NAME_FORMAT));
        }
        LOG.info(
                "DM-SAML>> SAML service provider details set for issuer {} with qualifier {}. LoginPageURL: {}, RequestedClaims: {}, RequestedClaimsList: {}, NameIdClaimUri: {}",
                serviceProviderDO.getIssuer(), serviceProviderDO.getIssuerQualifier(), serviceProviderDO.getLoginPageURL(), serviceProviderDO.getRequestedClaims(),
                serviceProviderDO.getRequestedClaimsList(), serviceProviderDO.getNameIdClaimUri());

        return serviceProviderDO;
    }

    private boolean isTransientException(Exception e) {

        Throwable rootCause = ExceptionUtils.getRootCause(e);
        return rootCause instanceof SQLTransientException || rootCause != null && rootCause.getMessage() != null &&
                rootCause.getMessage().contains("Connection reset by peer");
    }
}
