Skip to content

Commit bd6e1f9

Browse files
authored
[Destinations] Cross Level Destination Support (#890)
1 parent da94c48 commit bd6e1f9

File tree

8 files changed

+233
-89
lines changed

8 files changed

+233
-89
lines changed

cloudplatform/connectivity-destination-service/src/main/java/com/sap/cloud/sdk/cloudplatform/connectivity/DestinationService.java

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,10 @@
5151
@SuppressWarnings( "PMD.TooManyStaticImports" )
5252
public class DestinationService implements DestinationLoader
5353
{
54-
private static final String PATH_DEFAULT = "/destinations/";
55-
56-
private static final String PATH_SERVICE_INSTANCE = "/instanceDestinations";
57-
58-
private static final String PATH_SUBACCOUNT = "/subaccountDestinations";
54+
private static final String PATH_DEFAULT = "/v1/destinations/";
55+
private static final String PATH_V2 = "/v2/destinations/";
56+
private static final String PATH_SERVICE_INSTANCE = "/v1/instanceDestinations";
57+
private static final String PATH_SUBACCOUNT = "/v1/subaccountDestinations";
5958

6059
static final TimeLimiterConfiguration DEFAULT_TIME_LIMITER =
6160
TimeLimiterConfiguration.of().timeoutDuration(Duration.ofSeconds(6));
@@ -128,7 +127,13 @@ Destination loadAndParseDestination( final String destName, final DestinationOpt
128127
throws DestinationAccessException,
129128
DestinationNotFoundException
130129
{
131-
final String servicePath = PATH_DEFAULT + destName;
130+
final String servicePath =
131+
DestinationServiceOptionsAugmenter
132+
.getCrossLevelScope(options)
133+
.map(DestinationServiceOptionsAugmenter.CrossLevelScope::getSuffix)
134+
.map(s -> PATH_V2 + destName + s)
135+
.getOrElse(PATH_DEFAULT + destName);
136+
132137
final Function<DestinationRetrievalStrategy, DestinationServiceV1Response> destinationRetriever =
133138
strategy -> resilientCall(() -> retrieveDestination(strategy, servicePath), singleDestResilience);
134139

@@ -199,9 +204,9 @@ public Collection<DestinationProperties> getAllDestinationProperties()
199204
* In case there exists a destination with the same name on service instance and on sub-account level, the
200205
* destination at service instance level takes precedence.
201206
*
202-
* @return A list of destination properties.
203207
* @param retrievalStrategy
204208
* Strategy for loading destinations in a multi-tenant application.
209+
* @return A list of destination properties.
205210
* @since 5.12.0
206211
*/
207212
@Nonnull
@@ -648,9 +653,8 @@ public static void disableExpiration()
648653
* <strong>Caution:</strong> Using this operation will lead to a re-creation of the destination cache. As a
649654
* consequence, all existing cache entries will be lost.
650655
*
651-
* @deprecated since 5.2.0. Change detection mode is enabled by default
652-
*
653656
* @since 4.7.0
657+
* @deprecated since 5.2.0. Change detection mode is enabled by default
654658
*/
655659
@Deprecated
656660
public static void enableChangeDetection()

cloudplatform/connectivity-destination-service/src/main/java/com/sap/cloud/sdk/cloudplatform/connectivity/DestinationServiceAdapter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
@Slf4j
3838
class DestinationServiceAdapter
3939
{
40-
private static final String SERVICE_PATH = "destination-configuration/v1";
40+
private static final String SERVICE_PATH = "destination-configuration";
4141

4242
@Nonnull
4343
@Getter( AccessLevel.PACKAGE )

cloudplatform/connectivity-destination-service/src/main/java/com/sap/cloud/sdk/cloudplatform/connectivity/DestinationServiceOptionsAugmenter.java

Lines changed: 76 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@
55

66
import javax.annotation.Nonnull;
77

8+
import com.google.common.annotations.Beta;
9+
810
import io.vavr.control.Option;
911
import lombok.NoArgsConstructor;
12+
import lombok.RequiredArgsConstructor;
1013
import lombok.extern.slf4j.Slf4j;
1114

1215
/**
@@ -20,6 +23,7 @@ public class DestinationServiceOptionsAugmenter implements DestinationOptionsAug
2023
static final String DESTINATION_TOKEN_EXCHANGE_STRATEGY_KEY = "scp.cf.destinationTokenExchangeStrategy";
2124
static final String X_REFRESH_TOKEN_KEY = "x-refresh-token";
2225
static final String X_FRAGMENT_KEY = "X-fragment-name";
26+
static final String CROSS_LEVEL_SETTING = "crossLevelSetting";
2327

2428
private final Map<String, Object> parameters = new HashMap<>();
2529

@@ -105,6 +109,65 @@ public DestinationServiceOptionsAugmenter fragmentName( @Nonnull final String fr
105109
return this;
106110
}
107111

112+
/**
113+
* Enable <a href=
114+
* "https://help.sap.com/docs/connectivity/sap-btp-connectivity-cf/referring-resources-using-rest-api">cross-level
115+
* consumption of destinations</a>. <strong>Note: This is an experimental feature and may not function for all
116+
* destination types.</strong>
117+
*
118+
* @param scope
119+
* Set the scope where to look up the destination. This scope is only applied to the destination itself.
120+
* The scopes for fragments or destination chain references have to be set separately.
121+
* @return The same augmenter that called this method.
122+
* @since 5.22.0
123+
*/
124+
@Beta
125+
@Nonnull
126+
public DestinationServiceOptionsAugmenter crossLevelConsumption( @Nonnull final CrossLevelScope scope )
127+
{
128+
parameters.put(CROSS_LEVEL_SETTING, scope);
129+
return this;
130+
}
131+
132+
/**
133+
* Enable cross-level consumption of destinations.
134+
*
135+
* @since 5.22.0
136+
*/
137+
@Beta
138+
@RequiredArgsConstructor
139+
public enum CrossLevelScope
140+
{
141+
/**
142+
* Use the destination from the current subaccount.
143+
*/
144+
SUBACCOUNT("subaccount"),
145+
/**
146+
* Use the destination from the provider subaccount. Behaves identical to {@link #SUBACCOUNT}, if the current
147+
* tenant is the provider tenant, or the strategy {@link DestinationServiceRetrievalStrategy#ALWAYS_PROVIDER} is
148+
* used.
149+
*/
150+
PROVIDER_SUBACCOUNT("provider_subaccount"),
151+
/**
152+
* Use the destination from the destination service instance for the current tenant.
153+
*/
154+
INSTANCE("instance"),
155+
/**
156+
* Use the destination from the destination service instance for the provider tenant. Behaves identical to
157+
* {@link #INSTANCE}, if the current tenant is the provider tenant, or the strategy
158+
* {@link DestinationServiceRetrievalStrategy#ALWAYS_PROVIDER} is used.
159+
*/
160+
PROVIDER_INSTANCE("provider_instance");
161+
162+
private final String identifier;
163+
164+
@Nonnull
165+
String getSuffix()
166+
{
167+
return "@" + identifier;
168+
}
169+
}
170+
108171
@Override
109172
public void augmentBuilder( @Nonnull final DestinationOptions.Builder builder )
110173
{
@@ -127,9 +190,9 @@ public static Option<DestinationServiceRetrievalStrategy> getRetrievalStrategy(
127190
{
128191
final Option<Object> strategy = options.get(DESTINATION_RETRIEVAL_STRATEGY_KEY);
129192

130-
if( strategy.isDefined() && strategy.get() instanceof String ) {
193+
if( strategy.isDefined() && strategy.get() instanceof String str ) {
131194
return Option
132-
.of(DestinationServiceRetrievalStrategy.ofIdentifier((String) strategy.get()))
195+
.of(DestinationServiceRetrievalStrategy.ofIdentifier(str))
133196
.onEmpty(() -> log.warn("Unsupported destination retrieval strategy: {}", strategy.get()));
134197
}
135198

@@ -150,9 +213,9 @@ public static Option<DestinationServiceTokenExchangeStrategy> getTokenExchangeSt
150213
{
151214
final Option<Object> strategy = options.get(DESTINATION_TOKEN_EXCHANGE_STRATEGY_KEY);
152215

153-
if( strategy.isDefined() && strategy.get() instanceof String ) {
216+
if( strategy.isDefined() && strategy.get() instanceof String str ) {
154217
return Option
155-
.of(DestinationServiceTokenExchangeStrategy.ofIdentifier((String) strategy.get()))
218+
.of(DestinationServiceTokenExchangeStrategy.ofIdentifier(str))
156219
.onEmpty(() -> log.warn("Unsupported token exchange strategy: {}", strategy.get()));
157220
}
158221

@@ -170,4 +233,13 @@ static Option<String> getFragmentName( @Nonnull final DestinationOptions options
170233
{
171234
return options.get(X_FRAGMENT_KEY).filter(String.class::isInstance).map(String.class::cast);
172235
}
236+
237+
@Nonnull
238+
static Option<CrossLevelScope> getCrossLevelScope( @Nonnull final DestinationOptions options )
239+
{
240+
return options
241+
.get(CROSS_LEVEL_SETTING)
242+
.filter(CrossLevelScope.class::isInstance)
243+
.map(CrossLevelScope.class::cast);
244+
}
173245
}

cloudplatform/connectivity-destination-service/src/test/java/com/sap/cloud/sdk/cloudplatform/connectivity/DestinationServiceAdapterTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ class DestinationServiceAdapterTest
7979
private static final String PROVIDER_TENANT_ID = "provider-tenant-id";
8080

8181
private static final String XSUAA_URL = "/xsuaa/oauth/token";
82-
private static final String DESTINATION_SERVICE_URL = "/destination-service/destination-configuration/v1/";
82+
private static final String DESTINATION_SERVICE_URL = "/destination-service/destination-configuration/";
8383
private static final String DESTINATION_RESPONSE = "{ response }";
8484

8585
private static final String GRANT_TYPE_JWT_BEARER = "urn:ietf:params:oauth:grant-type:jwt-bearer";

cloudplatform/connectivity-destination-service/src/test/java/com/sap/cloud/sdk/cloudplatform/connectivity/DestinationServiceAuthenticationTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ class DestinationServiceAuthenticationTest
4040
private static final String BASIC_AUTH = "Zm9vOmJhcg==";
4141
private static final String DESTINATION_NAME = "CXT-HTTP-OAUTH";
4242

43-
private static final String SERVICE_PATH_DESTINATION = "/destinations/" + DESTINATION_NAME;
43+
private static final String SERVICE_PATH_DESTINATION = "/v1/destinations/" + DESTINATION_NAME;
4444

4545
@SuppressWarnings( "deprecation" )
4646
private static final DestinationOptions DESTINATION_RETRIEVAL_LOOKUP_EXCHANGE =

0 commit comments

Comments
 (0)