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
/*******************************************************************************
 *   © 2019-2024 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 - 2025 Weber Informatics LLC | Privacy Policy