Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

package software.amazon.smithy.java.aws.client.core.settings;

import software.amazon.smithy.java.client.core.ClientSetting;
import software.amazon.smithy.java.context.Context;

/**
* Configures an AWS Account ID.
*/
public interface AccountIdSetting<B extends ClientSetting<B>> extends RegionSetting<B> {
/**
* AWS Account ID to use.
*/
Context.Key<String> AWS_ACCOUNT_ID = Context.key("AWS Account ID");

/**
* Sets the AWS Account ID.
*
* @param awsAccountId AWS account ID to set.
* @return self
*/
default B awsAccountId(String awsAccountId) {
return putConfig(AWS_ACCOUNT_ID, awsAccountId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

package software.amazon.smithy.java.aws.client.core.settings;

import software.amazon.smithy.java.client.core.ClientSetting;
import software.amazon.smithy.java.context.Context;

/**
* Configures AWS specific endpoint settings.
*/
public interface EndpointSettings<B extends ClientSetting<B>> extends RegionSetting<B>, AccountIdSetting<B> {
/**
* If the SDK client is configured to use dual stack endpoints, defaults to false.
*/
Context.Key<Boolean> USE_DUAL_STACK = Context.key("Whether to use dual stack endpoint");

/**
* If the SDK client is configured to use FIPS-compliant endpoints, defaults to false.
*/
Context.Key<Boolean> USE_FIPS = Context.key("Whether to use FIPS endpoints");

/**
* The mode used when resolving Account ID based endpoints.
*/
Context.Key<String> ACCOUNT_ID_ENDPOINT_MODE = Context.key("Account ID endpoint mode");

/**
* Configures if the SDK uses dual stack endpoints. Defaults to false.
*
* @param useDualStack True to enable dual stack.
* @return self
*/
default B useDualStackEndpoint(boolean useDualStack) {
return putConfig(USE_DUAL_STACK, useDualStack);
}

/**
* Configures if the SDK uses FIPS endpoints. Defaults to false.
*
* @param useFips True to enable FIPS endpoints.
* @return self
*/
default B useFipsEndpoint(boolean useFips) {
return putConfig(USE_FIPS, useFips);
}

/**
* Sets the account ID endpoint mode for endpoint resolution.
*
* @param accountIdEndpointMode Account ID based endpoint resolution mode.
* @return self
*/
default B accountIdEndpointMode(String accountIdEndpointMode) {
return putConfig(ACCOUNT_ID_ENDPOINT_MODE, accountIdEndpointMode);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

package software.amazon.smithy.java.aws.client.core.settings;

import software.amazon.smithy.java.client.core.ClientSetting;
import software.amazon.smithy.java.context.Context;

/**
* Configures AWS specific endpoint settings.
*/
public interface S3EndpointSettings<B extends ClientSetting<B>> extends EndpointSettings<B> {
/**
* If the SDK client is configured to use S3 transfer acceleration, defaults to false.
*/
Context.Key<Boolean> S3_ACCELERATE = Context.key("AWS::S3::Accelerate");

/**
* If the SDK client is configured to not use S3's multi-region access points, defaults to false.
*/
Context.Key<Boolean> S3_DISABLE_MULTI_REGION_ACCESS_POINTS = Context.key("AWS::S3::DisableMultiRegionAccessPoints");

/**
* If the SDK client is configured to use solely S3 path style routing, defaults to false.
*/
Context.Key<Boolean> S3_FORCE_PATH_STYLE = Context.key("AWS::S3::ForcePathStyle");

/**
* If the SDK client is configured to use S3 bucket ARN regions or raise an error when the bucket ARN and client
* region differ, defaults to true.
*/
Context.Key<Boolean> S3_USE_ARN_REGION = Context.key("AWS::S3::UseArnRegion");

/**
* If the SDK client is configured to use S3's global endpoint instead of the regional us-east-1 endpoint,
* defaults to false.
*/
Context.Key<Boolean> S3_USE_GLOBAL_ENDPOINT = Context.key("AWS::S3::UseGlobalEndpoint");

/**
* If the SDK client is configured to use S3 Control bucket ARN regions or raise an error when the bucket ARN
* and client region differ, defaults to true.
*/
Context.Key<Boolean> S3_CONTROL_USE_ARN_REGION = Context.key("AWS::S3Control::UseArnRegion");

/**
* Configures if the SDK client is configured to use S3 transfer acceleration, defaults to false.
*
* @param useS3Accelerate True to enable.
* @return self
*/
default B s3useAccelerate(boolean useS3Accelerate) {
return putConfig(S3_ACCELERATE, useS3Accelerate);
}

/**
* If the SDK client is configured to not use S3's multi-region access points, defaults to false.
*
* @param value True to disable MRAP.
* @return self
*/
default B s3disableMultiRegionAccessPoints(boolean value) {
return putConfig(S3_DISABLE_MULTI_REGION_ACCESS_POINTS, value);
}

/**
* If the SDK client is configured to use solely S3 path style routing, defaults to false.
*
* @param usePathStyle True to force path style.
* @return self
*/
default B s3forcePathStyle(boolean usePathStyle) {
return putConfig(S3_FORCE_PATH_STYLE, usePathStyle);
}

/**
* If the SDK client is configured to use S3 bucket ARN regions or raise an error when the bucket ARN and client
* region differ, defaults to true.
*
* @param useArnRegion True to use ARN region.
* @return self
*/
default B s3useArnRegion(boolean useArnRegion) {
return putConfig(S3_USE_ARN_REGION, useArnRegion);
}

/**
* If the SDK client is configured to use S3's global endpoint instead of the regional us-east-1 endpoint,
* defaults to false.
*
* @param useGlobalEndpoint True to enable global endpoint.
* @return self
*/
default B s3useGlobalEndpoint(boolean useGlobalEndpoint) {
return putConfig(S3_USE_GLOBAL_ENDPOINT, useGlobalEndpoint);
}

/**
* If the SDK client is configured to use S3 Control bucket ARN regions or raise an error when the bucket ARN
* and client region differ, defaults to true.
*
* @param useArnRegion True to enable S3 control ARN region.
* @return self
*/
default B s3controlUseArnRegion(boolean useArnRegion) {
return putConfig(S3_CONTROL_USE_ARN_REGION, useArnRegion);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

package software.amazon.smithy.java.aws.client.core.settings;

import software.amazon.smithy.java.client.core.ClientSetting;
import software.amazon.smithy.java.context.Context;

/**
* Configures AWS specific endpoint settings.
*/
public interface StsEndpointSettings<B extends ClientSetting<B>> extends EndpointSettings<B> {
/**
* If the SDK client is configured to use STS' global endpoint instead of the regional us-east-1 endpoint,
* defaults to false.
*/
Context.Key<Boolean> STS_USE_GLOBAL_ENDPOINT = Context.key("AWS::STS::UseGlobalEndpoint");

/**
* Configures if if the SDK client is configured to use STS' global endpoint instead of the regional us-east-1
* endpoint, defaults to false.
*
* @param useGlobalEndpoint True to enable global endpoints.
* @return self
*/
default B stsUseGlobalEndpoint(boolean useGlobalEndpoint) {
return putConfig(STS_USE_GLOBAL_ENDPOINT, useGlobalEndpoint);
}
}
42 changes: 42 additions & 0 deletions aws/client/aws-client-rulesengine/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
plugins {
id("smithy-java.module-conventions")
id("me.champeau.jmh") version "0.7.3"
}

description = "This module provides AWS-Specific client rules engine functionality"

extra["displayName"] = "Smithy :: Java :: AWS :: Client :: Rules Engine"
extra["moduleName"] = "software.amazon.smithy.java.aws.client.rulesengine"

dependencies {
api(project(":aws:client:aws-client-core"))
api(project(":client:client-rulesengine"))
api(libs.smithy.aws.endpoints)

testImplementation(libs.smithy.aws.traits)
testImplementation(project(":aws:client:aws-client-restxml"))
testImplementation(project(":aws:client:aws-client-restjson"))
testImplementation(project(":client:dynamic-client"))
}

// Share the S3 model between JMH and tests.
sourceSets {
val sharedResources = "src/shared-resources"

named("test") {
resources.srcDir(sharedResources)
}

named("jmh") {
resources.srcDir(sharedResources)
}
}

jmh {
warmupIterations = 3
iterations = 5
fork = 1
profilers.add("async:output=flamegraph")
// profilers.add("gc")
duplicateClassesStrategy = DuplicatesStrategy.EXCLUDE // don't dump a bunch of warnings.
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

package software.amazon.smithy.java.aws.client.rulesengine;

import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import software.amazon.smithy.java.aws.client.core.settings.EndpointSettings;
import software.amazon.smithy.java.client.core.auth.scheme.AuthSchemeResolver;
import software.amazon.smithy.java.client.core.endpoint.EndpointResolver;
import software.amazon.smithy.java.client.core.endpoint.EndpointResolverParams;
import software.amazon.smithy.java.client.rulesengine.EndpointRulesPlugin;
import software.amazon.smithy.java.client.rulesengine.RulesEngineBuilder;
import software.amazon.smithy.java.context.Context;
import software.amazon.smithy.java.core.serde.document.Document;
import software.amazon.smithy.java.dynamicclient.DynamicClient;
import software.amazon.smithy.model.Model;
import software.amazon.smithy.model.loader.ModelAssembler;
import software.amazon.smithy.model.pattern.UriPattern;
import software.amazon.smithy.model.shapes.ServiceShape;
import software.amazon.smithy.model.shapes.Shape;
import software.amazon.smithy.model.shapes.ShapeId;
import software.amazon.smithy.model.traits.HttpTrait;
import software.amazon.smithy.model.transform.ModelTransformer;

@State(Scope.Benchmark)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@BenchmarkMode(Mode.AverageTime)
public class Bench {
private DynamicClient client;
private EndpointResolver endpointResolver;
private EndpointResolverParams endpointParams;

private Model model;
private ServiceShape service;
private final RulesEngineBuilder engine = new RulesEngineBuilder();

@Setup
public void setup() {
model = Model.assembler()
.discoverModels()
.addImport(ResolverTest.class.getResource("s3.json"))
.putProperty(ModelAssembler.ALLOW_UNKNOWN_TRAITS, true)
.assemble()
.unwrap();
model = customizeS3Model(model);
service = model.expectShape(ShapeId.from("com.amazonaws.s3#AmazonS3"), ServiceShape.class);

var plugin = EndpointRulesPlugin.create(engine);

client = DynamicClient.builder()
.model(model)
.service(service.getId())
.authSchemeResolver(AuthSchemeResolver.NO_AUTH)
.addPlugin(plugin)
.build();
endpointResolver = client.config().endpointResolver();

var inputValue = client.createStruct(ShapeId.from("com.amazonaws.s3#GetObjectRequest"),
Document.of(Map.of(
"Bucket",
Document.of("miked"),
"Key",
Document.of("bar"))));

var ctx = Context.create();
ctx.put(EndpointSettings.REGION, "us-east-1");
//ctx.put(EndpointRulesPlugin.ADDITIONAL_ENDPOINT_PARAMS, Map.of("UseFIPS", true, "UseDualStack", true));

endpointParams = EndpointResolverParams.builder()
.context(ctx)
.inputValue(inputValue)
.operation(client.getOperation("GetObject"))
.build();
}

// S3 requires a customization to remove buckets from the path :(
private static Model customizeS3Model(Model m) {
return ModelTransformer.create().mapShapes(m, s -> {
if (s.isOperationShape()) {
var httpTrait = s.getTrait(HttpTrait.class).orElse(null);
if (httpTrait != null && httpTrait.getUri().getLabel("Bucket").isPresent()) {
// Remove the bucket from the URI pattern.
var uriString = httpTrait.getUri().toString().replace("{Bucket}", "");
uriString = uriString.replace("//", "/");
var newUri = UriPattern.parse(uriString);
var newHttpTrait = httpTrait.toBuilder().uri(newUri).build();
return Shape.shapeToBuilder(s).addTrait(newHttpTrait).build();
}
}
return s;
});
}

@Benchmark
public Object evaluate() throws Exception {
return endpointResolver.resolveEndpoint(endpointParams).get();
}
}
Loading
Loading