All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sap.cloud.mt.subscription.SubscriberStreamlinedMtx Maven / Gradle / Ivy

There is a newer version: 3.3.1
Show newest version
/******************************************************************************
 * © 2020 SAP SE or an SAP affiliate company. All rights reserved.            *
 ******************************************************************************/
package com.sap.cloud.mt.subscription;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sap.cloud.mt.subscription.HanaEncryptionTool.DbEncryptionMode;
import com.sap.cloud.mt.subscription.exceptions.AuthorityError;
import com.sap.cloud.mt.subscription.exceptions.InternalError;
import com.sap.cloud.mt.subscription.exceptions.NotFound;
import com.sap.cloud.mt.subscription.exceptions.ParameterError;
import com.sap.cloud.mt.subscription.exits.Exits;
import com.sap.cloud.mt.subscription.json.ApplicationDependency;
import com.sap.cloud.mt.subscription.json.DeletePayload;
import com.sap.cloud.mt.subscription.json.SubscriptionPayload;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

public class SubscriberStreamlinedMtx implements Subscriber {
    //Magic tenant id that represents all tenants
    public static final String ALL_TENANTS = "all";
    private static final Logger logger = LoggerFactory.getLogger(SubscriberStreamlinedMtx.class);
    private static final String NO_SAAS_REGISTRY_PROVIDED = "No saas registry provided";
    private static final String ID = "ID";
    private final Exits exits;
    //Used to execute scope checks
    private final SecurityChecker securityChecker;
    //Proxy used to communicate with the saas registry service
    private final Optional saasRegistry;
    //Proxy for mtx provisioning service
    private final ProvisioningService provisioningService;
    private final InstanceLifecycleManager instanceLifecycleManager;
    private final MtxTools mtxTools;
    private final String baseUiUrl;
    private final String urlSeparator;
    private final boolean withoutAuthorityCheck;

    private SubscriberStreamlinedMtx(Exits exits,
                                     String baseUiUrl, String urlSeparator, SecurityChecker securityChecker, SaasRegistry saasRegistry,
                                     ProvisioningService provisioningService,
                                     InstanceLifecycleManager instanceLifecycleManager,
                                     boolean withoutAuthorityCheck, DbEncryptionMode hanaEncryptionMode) throws InternalError {
        this.baseUiUrl = baseUiUrl;
        this.urlSeparator = urlSeparator;
        this.exits = exits;
        this.saasRegistry = Optional.ofNullable(saasRegistry);
        this.instanceLifecycleManager = instanceLifecycleManager;
        if (exits.getUnSubscribeExit() == null) throw new InternalError("No unsubscribe exit found");
        this.securityChecker = securityChecker;
        this.mtxTools = new MtxTools(securityChecker, baseUiUrl, urlSeparator, provisioningService.getServiceSpecification().getPolling(), hanaEncryptionMode);
        this.provisioningService = provisioningService;
        this.withoutAuthorityCheck = withoutAuthorityCheck;
    }

    @Override
    public String subscribe(String tenantId, SubscriptionPayload subscriptionPayload)
            throws InternalError, ParameterError, AuthorityError {
        return mtxTools.subscribe(tenantId,
                instanceCreationOptions -> provisioningService.subscribe(tenantId, subscriptionPayload, instanceCreationOptions),
                provisioningService::determineJobStatus,
                subscriptionPayload,
                withoutAuthorityCheck, exits);
    }

    @Override
    public String getSubscribeUrl(SubscriptionPayload subscriptionPayload) throws InternalError, ParameterError, AuthorityError {
        if (!withoutAuthorityCheck) {
            securityChecker.checkSubscriptionAuthority();
        }
        return Tools.getApplicationUrl(subscriptionPayload, exits.getSubscribeExit()::uiURL, exits.getSubscribeExit()::uiURL, baseUiUrl, urlSeparator);
    }

    @Override
    public void unsubscribe(String tenantId, DeletePayload deletePayload) throws InternalError, ParameterError, AuthorityError {
        mtxTools.unsubscribe(tenantId,
                () -> provisioningService.unsubscribe(tenantId, deletePayload),
                provisioningService::determineJobStatus,
                deletePayload,
                withoutAuthorityCheck, exits);
    }

    @Override
    public List getApplicationDependencies() throws AuthorityError {
        if (!withoutAuthorityCheck) {
            securityChecker.checkSubscriptionAuthority();
        }
        return exits.getDependencyExit() != null ? exits.getDependencyExit().onGetDependencies() : new ArrayList<>();
    }

    @Override
    public void setupDbTables(List tenants) throws InternalError, AuthorityError, ParameterError {
        setupDbTables(tenants, false);
    }

    @Override
    public String setupDbTablesAsync(List tenants) throws InternalError, AuthorityError, ParameterError {
        try {
            return new ObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(setupDbTables(tenants, true));
        } catch (JsonProcessingException e) {
            throw new InternalError(e);
        }
    }

    @Override
    public String updateStatus(String jobId) throws InternalError, ParameterError, NotFound, AuthorityError {
        if (!withoutAuthorityCheck) {
            securityChecker.checkInitDbAuthority();
        }
        if (StringUtils.isBlank(jobId)) {
            logger.warn("An empty jobId was provided");
            return "{}";
        }
        if (!jobId.matches(Tools.SECURE_CHARS)) {
            throw new ParameterError("Job id contains illegal characters");
        }
        try {
            return new ObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(provisioningService.determineJobStatus(jobId));
        } catch (JsonProcessingException e) {
            throw new InternalError(e);
        }
    }


    @Override
    public void callSaasRegistry(boolean ok, String message, String applicationUrl, String saasRegistryUrl) throws InternalError {
        saasRegistry.orElseThrow(() -> new InternalError(NO_SAAS_REGISTRY_PROVIDED)).callBackSaasRegistry(ok, message, applicationUrl, saasRegistryUrl);
    }

    @Override
    public void checkAuthority(SecurityChecker.Authority authority) throws AuthorityError {
        securityChecker.checkAuthority(authority);
    }

    private Map setupDbTables(List tenants, boolean asynchronously) throws InternalError, AuthorityError, ParameterError {
        if (!withoutAuthorityCheck) {
            securityChecker.checkInitDbAuthority();
        }
        Tools.checkExternalTenantIds(tenants);
        if (tenants.isEmpty()) {
            return new HashMap<>();
        }
        if (exits.getInitDbExit() != null) {
            exits.getInitDbExit().onBeforeInitDb(tenants);
        }
        Set tenantSet = new HashSet<>(tenants);
        Map result;
        try {
            if (tenantSet.size() == 1 && tenants.get(0).equals(ALL_TENANTS)) {
                Set allTenants = instanceLifecycleManager.getAllTenants(true);
                if (allTenants.isEmpty()) {
                    return new HashMap<>();
                }
                tenantSet = allTenants;
            }
            result = provisioningService.upgrade(tenantSet, asynchronously);
            if (!asynchronously && exits.getInitDbExit() != null) {
                exits.getInitDbExit().onAfterInitDb(true);
            }
            if (result.containsKey(ID)) {
                // add field jobID to make it compatible to old version
                result.put("jobID", result.get(ID));
            }
            return result;
        } catch (InternalError e) {
            if (!asynchronously && exits.getInitDbExit() != null) {
                exits.getInitDbExit().onAfterInitDb(false);
            }
            throw e;
        }
    }

    public static final class Builder {
        private Exits exits;
        private SecurityChecker securityChecker;
        private SaasRegistry saasRegistry;
        private String baseUiUrl;
        private String urlSeparator;
        private ProvisioningService provisioningService;
        private InstanceLifecycleManager instanceLifecycleManager;
        private boolean withoutAuthorityCheck;
        private DbEncryptionMode hanaEncryptionMode;

        private Builder() {
        }

        public static Builder create() {
            return new Builder();
        }

        public Builder exits(Exits exits) {
            this.exits = exits;
            return this;
        }

        public Builder securityChecker(SecurityChecker securityChecker) {
            this.securityChecker = securityChecker;
            return this;
        }

        public Builder saasRegistry(SaasRegistry saasRegistry) {
            this.saasRegistry = saasRegistry;
            return this;
        }

        public Builder provisioningService(ProvisioningService provisioningService) {
            this.provisioningService = provisioningService;
            return this;
        }

        public Builder baseUiUrl(String baseUiUrl) {
            this.baseUiUrl = baseUiUrl;
            return this;
        }

        public Builder urlSeparator(String urlSeparator) {
            this.urlSeparator = urlSeparator;
            return this;
        }

        public Builder instanceLifecycleManager(InstanceLifecycleManager instanceLifecycleManager) {
            this.instanceLifecycleManager = instanceLifecycleManager;
            return this;
        }

        public Builder withoutAuthorityCheck(boolean withoutAuthorityCheck) {
            this.withoutAuthorityCheck = withoutAuthorityCheck;
            return this;
        }

        public Builder hanaEncryptionMode(DbEncryptionMode hanaEncryptionMode) {
            this.hanaEncryptionMode = hanaEncryptionMode;
            return this;
        }

        public SubscriberStreamlinedMtx build() throws InternalError {
            if (provisioningService == null) {
                throw new InternalError("No provisioning service provided");
            }
            if (exits == null) {
                throw new InternalError("No exits provided");
            }
            if (securityChecker == null) {
                throw new InternalError("No security checker provided");
            }
            if (instanceLifecycleManager == null) {
                throw new InternalError("No instance lifecycle manager provided");
            }
            return new SubscriberStreamlinedMtx(exits, baseUiUrl, urlSeparator, securityChecker, saasRegistry, provisioningService,
                    instanceLifecycleManager, withoutAuthorityCheck, hanaEncryptionMode);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy