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

com.sap.cds.feature.mt.MtUtils Maven / Gradle / Ivy

There is a newer version: 3.2.0
Show newest version
/**************************************************************************
 * (C) 2019-2024 SAP SE or an SAP affiliate company. All rights reserved. *
 **************************************************************************/
package com.sap.cds.feature.mt;


import java.nio.file.Paths;
import java.time.Duration;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.google.common.annotations.VisibleForTesting;
import com.sap.cds.services.environment.CdsProperties.MultiTenancy;
import com.sap.cds.services.runtime.CdsRuntime;
import com.sap.cds.services.utils.CdsErrorStatuses;
import com.sap.cds.services.utils.ErrorStatusException;
import com.sap.cds.services.utils.StringUtils;
import com.sap.cds.services.utils.environment.ServiceBindingUtils;
import com.sap.cds.services.utils.model.DynamicModelUtils;
import com.sap.cloud.environment.servicebinding.api.ServiceBinding;
import com.sap.cloud.mt.subscription.DbCredentials;
import com.sap.cloud.mt.subscription.DbCredentialsBuilder;
import com.sap.cloud.mt.subscription.DbIdentifiersSqLite;
import com.sap.cloud.mt.subscription.DbIdentifiersSql;
import com.sap.cloud.mt.subscription.InstanceLifecycleManager;
import com.sap.cloud.mt.subscription.InstanceLifecycleManagerBuilder;
import com.sap.cloud.mt.subscription.PollingParameters;
import com.sap.cloud.mt.subscription.ServiceManager;
import com.sap.cloud.mt.subscription.ServiceSpecification;
import com.sap.cloud.mt.subscription.exceptions.InternalError;

public class MtUtils {
	private static final String HANA_OFFERING_NAME = "hana";
	private static final String HANA_HDI_PLAN_NAME = "hdi-shared";

	static final String SERVICE_MANAGER = "service-manager";
	static final String MT_ENABLED = "mt-enabled";
	static final String SQLITE_BINDING_NAME = "mtx-sqlite";

	private final DynamicModelUtils dynamicModelUtils;
	private final MultiTenancy config;

	private final List bindings;
	private final ServiceBinding defaultBinding;

	public MtUtils(CdsRuntime runtime) {
		this.dynamicModelUtils = new DynamicModelUtils(runtime);
		this.config = runtime.getEnvironment().getCdsProperties().getMultiTenancy();

		// calculate bindings
		this.bindings = runtime.getEnvironment().getServiceBindings()
				.filter(b -> isServiceManagerBinding(b) || isSchemaBasedMtBinding(b))
				.collect(Collectors.toList());

		String bindingName = runtime.getEnvironment().getCdsProperties().getDataSource().getBinding();
		if (StringUtils.isEmpty(bindingName)) {
			if (bindings.size() == 1) {
				defaultBinding = bindings.get(0);
			} else if (bindings.size() > 1) {
				throw new ErrorStatusException(CdsErrorStatuses.NO_UNIQUE_DATASOURCE_SERVICE);
			} else {
				defaultBinding = null;
			}
		} else {
			defaultBinding = bindings.stream().filter(b -> b.getName().get().equals(bindingName)).findFirst().orElse(null);
		}
	}

	public boolean requiresSubscription() {
		boolean deployerConfigured = hasDeployer();
		return (defaultBinding != null && (deployerConfigured || isSchemaBasedMtBinding(defaultBinding)))
				|| (isSqliteDataSourceEnabled() && deployerConfigured);
	}

	@SuppressWarnings("deprecation")
	private boolean hasDeployer() {
		boolean dynamicDeployer = !StringUtils.isEmpty(config.getDeployer().getUrl());
		boolean provisioningService = isProvisioningServiceEnabled();
		if (dynamicDeployer && provisioningService) {
			throw new IllegalArgumentException("Either Sidecar/ProvisioningService or Deployer URL can be specified");
		}
		return dynamicDeployer || provisioningService;
	}

	// ProvisioningService:

	public boolean isProvisioningServiceEnabled() {
		return !StringUtils.isEmpty(getProvisioningServiceUrl());
	}

	public String getProvisioningServiceUrl() {
		return !StringUtils.isEmpty(config.getProvisioning().getUrl()) ? config.getProvisioning().getUrl() : config.getSidecar().getUrl();
	}

	// Bindings & InstanceLifecycleManagers:

	public InstanceLifecycleManager createDefaultInstanceLifecycleManager() {
		if (defaultBinding != null) {
			return createInstanceLifecycleManager(defaultBinding);
		} else if (isSqliteDataSourceEnabled()) {
			return createInstanceLifecycleManagerSqlite();
		}
		return null;
	}

	public Map createInstanceLifecycleManagers() {
		Map ilms = new HashMap<>();
		for (ServiceBinding binding : bindings) {
			ilms.put(binding.getName().get(), createInstanceLifecycleManager(binding)); // NOSONAR
		}
		if (isSqliteDataSourceEnabled()) {
			ilms.put(SQLITE_BINDING_NAME, createInstanceLifecycleManagerSqlite());
		}
		return ilms;
	}

	private boolean isSqliteDataSourceEnabled() {
		return bindings.isEmpty() && !Boolean.FALSE.equals(config.getMock().isEnabled()) && (isProvisioningServiceEnabled() || Boolean.TRUE.equals(config.getMock().isEnabled()));
	}

	private boolean isServiceManagerBinding(ServiceBinding b) {
		return ServiceBindingUtils.matches(b, SERVICE_MANAGER);
	}

	private boolean isSchemaBasedMtBinding(ServiceBinding b) {
		return ServiceBindingUtils.matches(b, MT_ENABLED, null);
	}

	private InstanceLifecycleManager createInstanceLifecycleManagerSqlite() {
		InstanceLifecycleManagerBuilder builder = InstanceLifecycleManagerBuilder.create();
		String sqliteDirectory = config.getMock().getSqliteDirectory();
		if (!StringUtils.isEmpty(sqliteDirectory)) {
			builder.dbIdentifiers(new DbIdentifiersSqLite(Paths.get(sqliteDirectory)));
		} else {
			builder.dbIdentifiers(new DbIdentifiersSqLite(Paths.get(System.getProperty("user.dir"))));
		}
		try {
			return builder.build();
		} catch (InternalError internalError) {
			throw new ErrorStatusException(CdsErrorStatuses.MT_LIB_SETUP_FAILED, internalError);
		}
	}

	private InstanceLifecycleManager createInstanceLifecycleManager(ServiceBinding binding) {
		InstanceLifecycleManagerBuilder builder = InstanceLifecycleManagerBuilder.create();
		InstanceLifecycleManager newIlm;
		if (isServiceManagerBinding(binding)) {
			builder.serviceManager(createServiceManager(binding));
			builder.smCacheRefreshInterval(config.getServiceManager().getCacheRefreshInterval());
			builder.acceptInstancesWithoutTenant(config.getServiceManager().getAcceptInstancesWithoutTenant().isEnabled());
			builder.smCacheResilienceConfig(dynamicModelUtils.getResilienceConfig());
			try {
				newIlm = builder.build();
			} catch (InternalError internalError) {
				throw new ErrorStatusException(CdsErrorStatuses.INSTANCE_MANAGER_CLIENT_FAILED, binding.getName().get(), internalError); // NOSONAR
			}
		} else {
			try {
				DbCredentials dbCredentials = DbCredentialsBuilder.create()
						.credentials(binding.getCredentials())
						.build();
				builder.dbIdentifiers(new DbIdentifiersSql(Collections.singletonList(dbCredentials)));
				newIlm = builder.build();
			} catch (InternalError internalError) {
				throw new ErrorStatusException(CdsErrorStatuses.MT_LIB_SETUP_FAILED, internalError.getMessage(), internalError);
			}
		}
		return newIlm;
	}

	@VisibleForTesting
	ServiceManager createServiceManager(ServiceBinding binding) {
		try {
			return new ServiceManager(binding,
					ServiceSpecification.Builder.create()
							.polling(PollingParameters.Builder.create()
									.interval(Duration.ofSeconds(10))
									.timeout(Duration.ofMinutes(20))
									.build())
							.resilienceConfig(dynamicModelUtils.getResilienceConfig())
							.build(),
					HANA_OFFERING_NAME, HANA_HDI_PLAN_NAME);
		} catch (InternalError e) {
			throw new ErrorStatusException(CdsErrorStatuses.INSTANCE_MANAGER_CLIENT_FAILED, binding.getName().get(), e); // NOSONAR
		}
	}

	@VisibleForTesting
	ServiceBinding getDefaultBinding() {
		return defaultBinding;
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy