
com.sap.cloud.sdk.cloudplatform.connectivity.ScpNeoDestinationFacade Maven / Gradle / Ivy
Show all versions of connectivity-scp-neo Show documentation
/*
* Copyright (c) 2020 SAP SE or an SAP affiliate company. All rights reserved.
*/
package com.sap.cloud.sdk.cloudplatform.connectivity;
import static com.sap.cloud.sdk.cloudplatform.connectivity.DestinationRetrievalStrategy.ALWAYS_PROVIDER;
import static com.sap.cloud.sdk.cloudplatform.connectivity.DestinationRetrievalStrategy.ALWAYS_SUBSCRIBER;
import static com.sap.cloud.sdk.cloudplatform.connectivity.DestinationRetrievalStrategy.PLATFORM_DEFAULT;
import static com.sap.cloud.sdk.cloudplatform.connectivity.DestinationRetrievalStrategy.SUBSCRIBER_THEN_PROVIDER;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.slf4j.Logger;
import com.google.common.collect.Sets;
import com.google.gson.JsonObject;
import com.sap.cloud.account.TenantContext;
import com.sap.cloud.sdk.cloudplatform.CloudPlatform;
import com.sap.cloud.sdk.cloudplatform.CloudPlatformAccessor;
import com.sap.cloud.sdk.cloudplatform.ScpNeoCloudPlatform;
import com.sap.cloud.sdk.cloudplatform.connectivity.exception.DestinationAccessException;
import com.sap.cloud.sdk.cloudplatform.connectivity.exception.DestinationNotFoundException;
import com.sap.cloud.sdk.cloudplatform.exception.CloudPlatformException;
import com.sap.cloud.sdk.cloudplatform.logging.CloudLoggerFactory;
import com.sap.cloud.sdk.cloudplatform.servlet.Property;
import com.sap.cloud.sdk.cloudplatform.servlet.RequestContext;
import com.sap.cloud.sdk.cloudplatform.servlet.RequestContextAccessor;
import com.sap.cloud.sdk.cloudplatform.servlet.RequestContextExecutor;
import com.sap.cloud.sdk.cloudplatform.servlet.RequestContextServletFilter;
import com.sap.cloud.sdk.cloudplatform.servlet.exception.RequestContextPropertyException;
import com.sap.cloud.sdk.cloudplatform.tenant.ScpNeoTenant;
import com.sap.cloud.sdk.cloudplatform.tenant.Tenant;
import com.sap.cloud.sdk.cloudplatform.tenant.TenantAccessor;
import com.sap.core.connectivity.api.configuration.ConnectivityConfiguration;
import com.sap.core.connectivity.api.configuration.DestinationConfiguration;
/**
* Facade providing access to destinations on SAP Cloud Platform Neo.
*
* In addition to reading destinations via the SAP CP Neo destination service API , this class provides the ability to
* read HTTP destination information from the environment variable "destinations". The environment variable is expected
* to be in JSON format (see {@link AbstractDestinationFacade}).
*/
public class ScpNeoDestinationFacade extends AbstractDestinationFacade
{
private static final Logger logger = CloudLoggerFactory.getLogger(ScpNeoDestinationFacade.class);
private final Set destinationNames = Sets.newConcurrentHashSet();
private ConnectivityConfiguration getConnectivityConfiguration()
throws DestinationAccessException
{
final Optional requestContext = RequestContextAccessor.getCurrentRequestContext();
if( !requestContext.isPresent() ) {
throw new DestinationAccessException(
"Failed to get "
+ ConnectivityConfiguration.class.getSimpleName()
+ ": no "
+ RequestContext.class.getSimpleName()
+ " available."
+ " Have you correctly configured a "
+ RequestContextServletFilter.class.getSimpleName()
+ " or have you wrapped your logic in a "
+ RequestContextExecutor.class.getSimpleName()
+ " when executing background tasks that are not triggered by a request?");
}
try {
final Optional> property =
requestContext.get().getProperty(
ScpNeoDestinationsRequestContextListener.PROPERTY_CONNECTIVITY_CONFIGURATION);
if( !property.isPresent() ) {
throw new DestinationAccessException(
"Failed to get "
+ ConnectivityConfiguration.class.getSimpleName()
+ ": "
+ RequestContext.class.getSimpleName()
+ " property '"
+ ScpNeoDestinationsRequestContextListener.PROPERTY_CONNECTIVITY_CONFIGURATION
+ "' is not present. "
+ "Please ensure that "
+ ScpNeoDestinationsRequestContextListener.class.getSimpleName()
+ " is available on the class path.");
}
@Nullable
final Exception exception = property.get().getException();
if( exception != null ) {
throw new DestinationAccessException(
"Failed to get " + ConnectivityConfiguration.class.getSimpleName() + ".",
exception);
}
return (ConnectivityConfiguration) property.get().getValue();
}
catch( final RequestContextPropertyException e ) {
throw new DestinationAccessException(
"Failed to get "
+ ConnectivityConfiguration.class.getSimpleName()
+ ": failed to get "
+ RequestContext.class.getSimpleName()
+ " property.",
e);
}
}
private DestinationConfiguration getDestinationConfiguration( final String destinationName )
throws DestinationAccessException,
DestinationNotFoundException
{
final ConnectivityConfiguration connectivityConfiguration = getConnectivityConfiguration();
try {
final DestinationRetrievalStrategy strategy = DestinationAccessor.getRetrievalStrategy(destinationName);
DestinationConfiguration destinationConfiguration = null;
if( strategy.equals(PLATFORM_DEFAULT) ) {
destinationConfiguration = connectivityConfiguration.getConfiguration(destinationName);
} else {
if( strategy.equals(ALWAYS_SUBSCRIBER) || strategy.equals(SUBSCRIBER_THEN_PROVIDER) ) {
destinationConfiguration =
connectivityConfiguration.getConfiguration(getCurrentAccountId(), destinationName);
}
if( strategy.equals(ALWAYS_PROVIDER)
|| (destinationConfiguration == null && strategy.equals(SUBSCRIBER_THEN_PROVIDER)) ) {
destinationConfiguration =
connectivityConfiguration.getConfiguration(getProviderAccountId(), destinationName);
}
}
if( destinationConfiguration == null ) {
throw new DestinationNotFoundException(destinationName);
}
return destinationConfiguration;
}
catch( final IllegalArgumentException | IllegalStateException e ) {
throw new DestinationAccessException(
"Failed to access configuration for destination '" + destinationName + "'.",
e);
}
}
/**
* {@inheritDoc}
*/
@Nonnull
@Override
public Class extends GenericDestination> getGenericDestinationClass()
{
return ScpNeoGenericDestination.class;
}
/**
* {@inheritDoc}
*/
@Nonnull
@Override
public Class extends Destination> getDestinationClass()
{
return ScpNeoDestination.class;
}
/**
* {@inheritDoc}
*/
@Nonnull
@Override
public Class extends RfcDestination> getRfcDestinationClass()
{
return ScpNeoRfcDestination.class;
}
/**
* {@inheritDoc}
*/
@Override
public void declareDestinations( @Nonnull final Collection destinationNames )
{
this.destinationNames.addAll(destinationNames);
}
private void warnIfEnvironmentVariableIsUsed()
{
if( logger.isWarnEnabled() ) {
logger.warn(
"Environment variable '"
+ AbstractDestinationFacade.VARIABLE_DESTINATIONS
+ "' is set. "
+ "Destinations will only be read from this variable. "
+ "Unset this variable to read destinations from the destination service on SAP Cloud Platform.");
}
}
/**
* {@inheritDoc}
*/
@Nonnull
@Override
public GenericDestination getGenericDestination( @Nonnull final String destinationName )
throws DestinationNotFoundException,
DestinationAccessException
{
// Note: we use a local variable that references JsonObject to make sure that
// the maven-dependency-plugin correctly detects the usage of Gson here.
final Map destinationsFromEnvironmentVariable = getDestinationsFromEnvironmentVariable();
if( destinationsFromEnvironmentVariable != null ) {
warnIfEnvironmentVariableIsUsed();
return super.getGenericDestination(destinationName);
}
final DestinationConfiguration destinationConfiguration = getDestinationConfiguration(destinationName);
final ScpNeoDestinationParser destinationParser = new ScpNeoDestinationParser(destinationConfiguration);
return new ScpNeoDestinationFactory(destinationConfiguration).create(destinationParser);
}
/**
* {@inheritDoc}
*/
@Nonnull
@Override
public Map getGenericDestinationsByName()
throws DestinationAccessException
{
if( getDestinationsFromEnvironmentVariable() != null ) {
warnIfEnvironmentVariableIsUsed();
return getDestinationsFromEnvironmentVariable(new ScpNeoDestinationFactory());
}
if( logger.isDebugEnabled() ) {
logger.debug("Resolving destinations by names: " + destinationNames + ".");
}
final Map result = new HashMap<>();
for( final String destinationName : destinationNames ) {
final DestinationConfiguration destinationConfiguration = getDestinationConfiguration(destinationName);
try {
final ScpNeoDestinationParser destinationParser = new ScpNeoDestinationParser(destinationConfiguration);
final GenericDestination destination =
new ScpNeoDestinationFactory(destinationConfiguration).create(destinationParser);
result.put(destinationName, destination);
if( logger.isDebugEnabled() ) {
logger.debug(
String.format(
"Successfully added %s destination '%s' to destination list.",
destination.getDestinationType().toString(),
destination.getName()));
}
}
catch( final DestinationNotFoundException e ) {
if( logger.isWarnEnabled() ) {
logger.warn(
"Failed to add destination '"
+ destinationName
+ "' to the result of getDestinationsByName(): destination not found. "
+ "This indicates a missing or incorrect destination configuration on Cloud platform side. "
+ "Correct the configuration of this destination or remove its declaration if obsolete.",
e);
}
}
}
if( logger.isDebugEnabled() ) {
logger.debug(String.format("Resolved %d destinations.", result.size()));
}
return result;
}
@Nonnull
private String getCurrentAccountId()
{
final Tenant tenant = TenantAccessor.getCurrentTenant();
if( tenant instanceof ScpNeoTenant ) {
final TenantContext tenantContext = ((ScpNeoTenant) tenant).getTenantContext();
return tenantContext.getTenant().getAccount().getId();
} else {
throw new CloudPlatformException(
"The current tenant is not an instance of "
+ ScpNeoTenant.class.getSimpleName()
+ ". Please make sure to specify a dependency to com.sap.cloud.s4hana.cloudplatform:tenant-scp-neo.");
}
}
@Nonnull
private String getProviderAccountId()
{
final CloudPlatform platform = CloudPlatformAccessor.getCloudPlatform();
if( platform instanceof ScpNeoCloudPlatform ) {
return ((ScpNeoCloudPlatform) platform).getProviderAccountId();
} else {
throw new CloudPlatformException(
"The current Cloud platform is not an instance of "
+ ScpNeoCloudPlatform.class.getSimpleName()
+ ". Please make sure to specify a dependency to com.sap.cloud.s4hana.cloudplatform:core-scp-neo.");
}
}
}