com.sap.cloud.sdk.cloudplatform.connectivity.ScpNeoDestination Maven / Gradle / Ivy
/*
* Copyright (c) 2018 SAP SE or an SAP affiliate company. All rights reserved.
*/
package com.sap.cloud.sdk.cloudplatform.connectivity;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.KeyStore;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.slf4j.Logger;
import com.google.common.base.Strings;
import com.netflix.hystrix.exception.HystrixBadRequestException;
import com.netflix.hystrix.exception.HystrixRuntimeException;
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.exception.CloudPlatformException;
import com.sap.cloud.sdk.cloudplatform.exception.ShouldNotHappenException;
import com.sap.cloud.sdk.cloudplatform.logging.CloudLoggerFactory;
import com.sap.cloud.sdk.cloudplatform.security.BasicCredentials;
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.DestinationConfiguration;
import lombok.Getter;
/**
* Destination used with the Neo platform.
*
* @see ScpNeoGenericDestination
* @see ScpNeoRfcDestination
*/
public class ScpNeoDestination extends AbstractDestination
{
private static final Logger logger = CloudLoggerFactory.getLogger(ScpNeoDestination.class);
private static final String SAP_CONNECTIVITY_CONSUMER_ACCOUNT = "SAP-Connectivity-ConsumerAccount";
private static final String SAP_CONNECTIVITY_SCC_LOCATION_ID_HEADER = "SAP-Connectivity-SCC-Location_ID";
@Getter
@Nullable
private final DestinationConfiguration destinationConfiguration;
@Nullable
private final String cloudConnectorLocationId;
public ScpNeoDestination(
@Nullable final DestinationConfiguration destinationConfiguration,
@Nonnull final String name,
@Nullable final String description,
@Nonnull final URI uri,
@Nonnull final AuthenticationType authenticationType,
@Nullable final BasicCredentials basicCredentials,
@Nonnull final ProxyType proxyType,
@Nullable final ProxyConfiguration proxyConfiguration,
final boolean isTrustingAllCertificates,
@Nullable final String trustStoreLocation,
@Nullable final String trustStorePassword,
@Nullable final String keyStoreLocation,
@Nullable final String keyStorePassword,
@Nullable final String cloudConnectorLocationId,
@Nonnull final Map propertiesByName )
{
super(
name,
description,
uri,
authenticationType,
basicCredentials,
proxyType,
proxyConfiguration,
isTrustingAllCertificates,
trustStoreLocation,
trustStorePassword,
keyStoreLocation,
keyStorePassword,
propertiesByName);
this.destinationConfiguration = destinationConfiguration;
this.cloudConnectorLocationId = cloudConnectorLocationId;
}
/**
* Creates a mocked {@link ScpNeoDestination} returning an empty destination name.
*
* This no-arguments constructor is required to ensure compatibility with mocking frameworks such as Mockito.
*/
private ScpNeoDestination()
{
this(
null,
"",
null,
URI.create(""),
AuthenticationType.NO_AUTHENTICATION,
null,
ProxyType.INTERNET,
null,
false,
null,
null,
null,
null,
null,
Collections.emptyMap());
}
/**
* Getter for the location identifier used by the SAP Cloud Connector.
*
* @return The location identifier.
*/
@Nonnull
public Optional getCloudConnectorLocationId()
{
return Optional.ofNullable(cloudConnectorLocationId);
}
@Nonnull
@Override
public Optional getTrustStore()
{
if( destinationConfiguration == null ) {
return Optional.empty();
}
return Optional.ofNullable(destinationConfiguration.getTrustStore());
}
@Nonnull
@Override
public Optional getKeyStore()
{
if( destinationConfiguration == null ) {
return Optional.empty();
}
return Optional.ofNullable(destinationConfiguration.getKeyStore());
}
private ProxyConfiguration getOnPremiseProxyConfiguration()
throws DestinationAccessException
{
final CloudPlatform cloudPlatform = CloudPlatformAccessor.getCloudPlatform();
if( !(cloudPlatform instanceof ScpNeoCloudPlatform) ) {
throw new ShouldNotHappenException(
"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.");
}
final ScpNeoCloudPlatform scpNeoCloudPlatform = (ScpNeoCloudPlatform) cloudPlatform;
try {
final String onPremiseProxyHost = scpNeoCloudPlatform.getOnPremiseProxyHost();
final int onPremiseProxyPort = scpNeoCloudPlatform.getOnPremiseProxyPort();
final URI uri = new URI("http://" + onPremiseProxyHost + ":" + onPremiseProxyPort);
final ProxyConfiguration proxyConfiguration = new ProxyConfiguration(uri);
if( logger.isDebugEnabled() ) {
logger.debug("Using on-premise proxy configuration: " + uri + ".");
}
return proxyConfiguration;
}
catch( final CloudPlatformException e ) {
throw new DestinationAccessException("Failed to get on-premise proxy host or port.", e);
}
catch( final URISyntaxException e ) {
throw new DestinationAccessException("Invalid on-premise proxy host or port.", e);
}
}
@Nonnull
@Override
public Optional getProxyConfiguration()
throws DestinationAccessException
{
if( getProxyType() == ProxyType.ON_PREMISE ) {
return Optional.of(getOnPremiseProxyConfiguration());
} else {
return Optional.ofNullable(proxyConfiguration);
}
}
private Collection getAuthenticationHeaders( @Nullable final URI requestUri )
throws DestinationAccessException
{
try {
return new GetAuthHeadersCommand(this, requestUri).execute();
}
catch( final HystrixRuntimeException | HystrixBadRequestException | IllegalStateException e ) {
throw new DestinationAccessException(
"Failed to get the request headers for destination \""
+ getName()
+ "\" (request URI: "
+ requestUri
+ ").",
e);
}
}
@Nullable
private String getCurrentAccountId()
{
final Optional currentTenant = TenantAccessor.getCurrentTenantIfAvailable();
if( !currentTenant.isPresent() ) {
if( logger.isDebugEnabled() ) {
logger.debug(
"Unable to determine current account identifier: tenant not available. "
+ "The connectivity header \""
+ SAP_CONNECTIVITY_CONSUMER_ACCOUNT
+ "\" will be omitted. "
+ "On-premise connectivity may not work in consumer accounts.");
}
return null;
}
final Tenant tenant = currentTenant.get();
if( !(tenant instanceof ScpNeoTenant) ) {
throw new ShouldNotHappenException(
"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.");
}
return ((ScpNeoTenant) tenant).getTenantContext().getTenant().getAccount().getId();
}
private Collection getOnPremiseProxyHeaders()
{
final List headers = new ArrayList<>();
@Nullable
final String currentAccountId = getCurrentAccountId();
if( !Strings.isNullOrEmpty(currentAccountId) ) {
headers.add(new Header(SAP_CONNECTIVITY_CONSUMER_ACCOUNT, currentAccountId));
}
if( !Strings.isNullOrEmpty(cloudConnectorLocationId) ) {
headers.add(new Header(SAP_CONNECTIVITY_SCC_LOCATION_ID_HEADER, cloudConnectorLocationId));
if( logger.isDebugEnabled() ) {
logger.debug(
"Successfully added "
+ SAP_CONNECTIVITY_SCC_LOCATION_ID_HEADER
+ " header with location identifier \""
+ cloudConnectorLocationId
+ "\".");
}
}
return headers;
}
@Nonnull
@Override
public List getHeaders( @Nullable final URI requestUri )
throws DestinationAccessException
{
final List headers = super.getHeaders(requestUri);
headers.addAll(getAuthenticationHeaders(requestUri));
if( ProxyType.ON_PREMISE == getProxyType() ) {
headers.addAll(getOnPremiseProxyHeaders());
}
return headers;
}
}