diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/model/ServiceClientConfigurationBuilderClass.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/model/ServiceClientConfigurationBuilderClass.java index 4fd0b5f85783..d73b58de43e0 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/model/ServiceClientConfigurationBuilderClass.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/model/ServiceClientConfigurationBuilderClass.java @@ -165,6 +165,10 @@ private void addLocalFieldForBuilderIfNeeded(Field field, TypeSpec.Builder build } private MethodSpec setterForField(Field field) { + MethodSpec fieldBuilderSetter = field.builderSetterImpl(); + if (fieldBuilderSetter != null) { + return fieldBuilderSetter.toBuilder().returns(builderInterface).build(); + } MethodSpec.Builder builder = baseSetterForField(field); if (field.isLocalField()) { builder.addAnnotation(Override.class); @@ -199,6 +203,12 @@ private MethodSpec getterForBuilderField(Field field) { private MethodSpec getterForField(Field field, String fieldName, boolean forDataGetter) { + MethodSpec fieldBuilderGetter = field.builderGetterImpl(); + if (fieldBuilderGetter != null) { + return fieldBuilderGetter.toBuilder() + .returns(field.type()) + .build(); + } MethodSpec.Builder builder = baseGetterForField(field); if (!forDataGetter && field.isLocalField()) { builder.addAnnotation(Override.class); diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/model/ServiceClientConfigurationClass.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/model/ServiceClientConfigurationClass.java index 962f0b552ac0..14f63bc3b9ed 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/model/ServiceClientConfigurationClass.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/model/ServiceClientConfigurationClass.java @@ -122,6 +122,12 @@ private void addLocalFieldForDataIfNeeded(Field field, TypeSpec.Builder builder) } private MethodSpec.Builder baseSetterForField(Field field) { + MethodSpec fieldBuilderSetter = field.builderSetter(); + if (fieldBuilderSetter != null) { + return fieldBuilderSetter.toBuilder() + .returns(className().nestedClass("Builder")); + } + MethodSpec.Builder builder = MethodSpec.methodBuilder(field.name()) .addModifiers(PUBLIC) .addParameter(field.type(), field.name()) @@ -138,6 +144,13 @@ private MethodSpec getterForDataField(Field field) { } private MethodSpec getterForField(Field field, String fieldName, boolean forDataGetter) { + MethodSpec fieldBuilderGetter = field.builderGetterImpl(); + if (fieldBuilderGetter != null) { + return fieldBuilderGetter.toBuilder() + .returns(field.type()) + .build(); + } + MethodSpec.Builder builder = baseGetterForField(field); if (!forDataGetter && field.isLocalField()) { builder.addAnnotation(Override.class); diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/model/ServiceClientConfigurationUtils.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/model/ServiceClientConfigurationUtils.java index ffc3d05c42bb..fc0719857795 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/model/ServiceClientConfigurationUtils.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/model/ServiceClientConfigurationUtils.java @@ -17,13 +17,18 @@ import com.squareup.javapoet.ClassName; import com.squareup.javapoet.CodeBlock; +import com.squareup.javapoet.MethodSpec; import com.squareup.javapoet.ParameterizedTypeName; import com.squareup.javapoet.TypeName; import com.squareup.javapoet.WildcardTypeName; import java.net.URI; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import javax.lang.model.element.Modifier; import software.amazon.awssdk.awscore.AwsServiceClientConfiguration; import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel; @@ -34,6 +39,7 @@ import software.amazon.awssdk.core.client.config.SdkClientConfiguration; import software.amazon.awssdk.core.client.config.SdkClientOption; import software.amazon.awssdk.endpoints.EndpointProvider; +import software.amazon.awssdk.http.auth.spi.scheme.AuthScheme; import software.amazon.awssdk.http.auth.spi.scheme.AuthSchemeProvider; import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity; import software.amazon.awssdk.identity.spi.IdentityProvider; @@ -132,7 +138,8 @@ private static List baseServiceClientConfigurationFields() { .optionClass(AwsClientOption.class) .optionValue(AwsClientOption.AWS_REGION) .build(), - credentialsProviderField() + credentialsProviderField(), + authSchemesField() ); } @@ -215,6 +222,78 @@ SdkClientOption.class, fieldName(SdkClientOption.IDENTITY_PROVIDERS, SdkClientOp return builder.build(); } + + private static Field authSchemesField() { + TypeName authSchemeGenericType = ParameterizedTypeName.get(ClassName.get(AuthScheme.class), + WildcardTypeName.subtypeOf(Object.class)); + TypeName authSchemesType = ParameterizedTypeName.get(ClassName.get(Map.class), ClassName.get(String.class), + authSchemeGenericType); + Field.Builder builder = Field.builder("authSchemes", + authSchemesType) + .doc("auth schemes") + .definingClass(SdkServiceClientConfiguration.class); + + builder.constructFromConfiguration( + CodeBlock.builder() + .addStatement("$T authSchemes = internalBuilder.option($T.$L)", + authSchemesType, SdkClientOption.class, + fieldName(SdkClientOption.AUTH_SCHEMES, SdkClientOption.class)) + .beginControlFlow("if (authSchemes != null)") + .addStatement("authSchemes = new $T<>(authSchemes)", HashMap.class) + .endControlFlow() + .addStatement("this.authSchemes = authSchemes") + .build() + ); + + builder.copyToConfiguration( + CodeBlock.builder() + .beginControlFlow("if (authSchemes != null &&" + + " !authSchemes.equals(internalBuilder.option($T.$L)))", + SdkClientOption.class, fieldName(SdkClientOption.AUTH_SCHEMES, + SdkClientOption.class)) + .addStatement("internalBuilder.option($T.$L, authSchemes())", + SdkClientOption.class, fieldName(SdkClientOption.AUTH_SCHEMES, + SdkClientOption.class)) + .endControlFlow() + .build() + ); + + builder.builderSetterImpl( + MethodSpec.methodBuilder("putAuthScheme") + .addModifiers(Modifier.PUBLIC) + .addAnnotation(Override.class) + .addParameter(authSchemeGenericType, "authScheme") + .beginControlFlow("if (authSchemes == null)") + .addStatement("authSchemes = new $T<>()", HashMap.class) + .endControlFlow() + .addStatement("authSchemes.put(authScheme.schemeId(), authScheme)") + .addStatement("return this") + .build() + ); + + builder.builderSetter( + MethodSpec.methodBuilder("putAuthScheme") + .addModifiers(Modifier.PUBLIC) + .addAnnotation(Override.class) + .addParameter(authSchemeGenericType, "authScheme") + .build() + ); + + builder.builderGetterImpl( + MethodSpec.methodBuilder("authSchemes") + .addModifiers(Modifier.PUBLIC) + .addAnnotation(Override.class) + .returns(authSchemesType) + .beginControlFlow("if (authSchemes == null)") + .addStatement("return $T.emptyMap()", Collections.class) + .endControlFlow() + .addStatement("return $T.unmodifiableMap(new $T<>(authSchemes))", Collections.class, HashMap.class) + .build() + ); + + return builder.build(); + } + static class Field { private final String name; private final TypeName type; @@ -225,6 +304,9 @@ static class Field { private final TypeName baseType; private final CodeBlock constructFromConfiguration; private final CodeBlock copyToConfiguration; + private final MethodSpec builderSetterImpl; + private final MethodSpec builderSetter; + private final MethodSpec builderGetterImpl; Field(Field.Builder builder) { this.name = Validate.paramNotNull(builder.name, "name"); @@ -236,6 +318,9 @@ static class Field { this.baseType = builder.baseType; this.constructFromConfiguration = builder.constructFromConfiguration; this.copyToConfiguration = builder.copyToConfiguration; + this.builderSetterImpl = builder.builderSetterImpl; + this.builderSetter = builder.builderSetter; + this.builderGetterImpl = builder.builderGetterImpl; } public boolean isLocalField() { @@ -278,6 +363,18 @@ public CodeBlock copyToConfiguration() { return copyToConfiguration; } + public MethodSpec builderSetterImpl() { + return builderSetterImpl; + } + + public MethodSpec builderSetter() { + return builderSetter; + } + + public MethodSpec builderGetterImpl() { + return builderGetterImpl; + } + public static Field.Builder builder() { return new Field.Builder(); } @@ -305,7 +402,9 @@ static class Builder { private TypeName baseType; private CodeBlock constructFromConfiguration; private CodeBlock copyToConfiguration; - + private MethodSpec builderSetterImpl; + private MethodSpec builderSetter; + private MethodSpec builderGetterImpl; public Field.Builder name(String name) { this.name = name; @@ -357,6 +456,21 @@ public Field.Builder copyToConfiguration(CodeBlock copyToConfiguration) { return this; } + public Field.Builder builderSetterImpl(MethodSpec builderSetter) { + this.builderSetterImpl = builderSetter; + return this; + } + + public Field.Builder builderSetter(MethodSpec builderSetter) { + this.builderSetter = builderSetter; + return this; + } + + public Field.Builder builderGetterImpl(MethodSpec builderGetterImpl) { + this.builderGetterImpl = builderGetterImpl; + return this; + } + public Field build() { if (value != null && optionClass != null) { optionName = fieldName(value, optionClass); diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/serviceclientconfiguration-builder.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/serviceclientconfiguration-builder.java index d784ec5cf825..b3c660909e86 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/serviceclientconfiguration-builder.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/serviceclientconfiguration-builder.java @@ -1,6 +1,9 @@ package software.amazon.awssdk.services.jsonprotocoltests.internal; import java.net.URI; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import software.amazon.awssdk.annotations.Generated; import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.awscore.client.config.AwsClientOption; @@ -8,6 +11,7 @@ import software.amazon.awssdk.core.client.config.SdkClientConfiguration; import software.amazon.awssdk.core.client.config.SdkClientOption; import software.amazon.awssdk.endpoints.EndpointProvider; +import software.amazon.awssdk.http.auth.spi.scheme.AuthScheme; import software.amazon.awssdk.http.auth.spi.scheme.AuthSchemeProvider; import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity; import software.amazon.awssdk.identity.spi.IdentityProvider; @@ -41,6 +45,8 @@ public static class BuilderImpl implements BuilderInternal { private IdentityProvider credentialsProvider; + private Map> authSchemes; + private BuilderImpl() { this.internalBuilder = SdkClientConfiguration.builder(); } @@ -53,6 +59,11 @@ private BuilderImpl(SdkClientConfiguration.Builder internalBuilder) { this.endpointOverride = internalBuilder.option(SdkClientOption.ENDPOINT); } this.credentialsProvider = internalBuilder.option(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER); + Map> authSchemes = internalBuilder.option(SdkClientOption.AUTH_SCHEMES); + if (authSchemes != null) { + authSchemes = new HashMap<>(authSchemes); + } + this.authSchemes = authSchemes; } /** @@ -142,6 +153,23 @@ public IdentityProvider credentialsProvider() return credentialsProvider; } + @Override + public JsonProtocolTestsServiceClientConfiguration.Builder putAuthScheme(AuthScheme authScheme) { + if (authSchemes == null) { + authSchemes = new HashMap<>(); + } + authSchemes.put(authScheme.schemeId(), authScheme); + return this; + } + + @Override + public Map> authSchemes() { + if (authSchemes == null) { + return Collections.emptyMap(); + } + return Collections.unmodifiableMap(new HashMap<>(authSchemes)); + } + /** * Sets the value for auth scheme provider */ @@ -190,6 +218,9 @@ public SdkClientConfiguration buildSdkClientConfiguration() { } internalBuilder.option(SdkClientOption.IDENTITY_PROVIDERS, identityProviders); } + if (authSchemes != null && !authSchemes.equals(internalBuilder.option(SdkClientOption.AUTH_SCHEMES))) { + internalBuilder.option(SdkClientOption.AUTH_SCHEMES, authSchemes()); + } return internalBuilder.build(); } } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/serviceclientconfiguration.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/serviceclientconfiguration.java index b71265026522..4c38f0d3a796 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/serviceclientconfiguration.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/serviceclientconfiguration.java @@ -1,11 +1,13 @@ package software.amazon.awssdk.services.jsonprotocoltests; import java.net.URI; +import java.util.Map; import software.amazon.awssdk.annotations.Generated; import software.amazon.awssdk.annotations.SdkPublicApi; import software.amazon.awssdk.awscore.AwsServiceClientConfiguration; import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; import software.amazon.awssdk.endpoints.EndpointProvider; +import software.amazon.awssdk.http.auth.spi.scheme.AuthScheme; import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity; import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.regions.Region; @@ -100,6 +102,15 @@ public interface Builder extends AwsServiceClientConfiguration.Builder { @Override IdentityProvider credentialsProvider(); + @Override + Builder putAuthScheme(AuthScheme authScheme); + + /** + * Gets the value for auth schemes + */ + @Override + Map> authSchemes(); + /** * Sets the value for auth scheme provider */ diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/AwsServiceClientConfiguration.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/AwsServiceClientConfiguration.java index 0f6146ce91ea..883405d8e3aa 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/AwsServiceClientConfiguration.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/AwsServiceClientConfiguration.java @@ -16,11 +16,15 @@ package software.amazon.awssdk.awscore; import java.net.URI; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import java.util.Objects; import software.amazon.awssdk.annotations.SdkPublicApi; import software.amazon.awssdk.core.SdkServiceClientConfiguration; import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; import software.amazon.awssdk.endpoints.EndpointProvider; +import software.amazon.awssdk.http.auth.spi.scheme.AuthScheme; import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity; import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.regions.Region; @@ -33,11 +37,13 @@ public abstract class AwsServiceClientConfiguration extends SdkServiceClientConf private final Region region; private final IdentityProvider credentialsProvider; + private final Map> authSchemes; protected AwsServiceClientConfiguration(Builder builder) { super(builder); this.region = builder.region(); this.credentialsProvider = builder.credentialsProvider(); + this.authSchemes = builder.authSchemes(); } /** @@ -55,12 +61,20 @@ public IdentityProvider credentialsProvider() return credentialsProvider; } + /** + * @return The configured map of auth schemes. + */ + public Map> authSchemes() { + return authSchemes; + } + @Override public int hashCode() { int result = 1; result = 31 * result + super.hashCode(); result = 31 * result + (region != null ? region.hashCode() : 0); result = 31 * result + (credentialsProvider != null ? credentialsProvider.hashCode() : 0); + result = 31 * result + (authSchemes != null ? authSchemes.hashCode() : 0); return result; } @@ -72,7 +86,8 @@ public boolean equals(Object o) { AwsServiceClientConfiguration that = (AwsServiceClientConfiguration) o; return Objects.equals(region, that.region) - && Objects.equals(credentialsProvider, that.credentialsProvider); + && Objects.equals(credentialsProvider, that.credentialsProvider) + && Objects.equals(authSchemes, that.authSchemes); } /** @@ -108,6 +123,9 @@ default Builder endpointProvider(EndpointProvider endpointProvider) { throw new UnsupportedOperationException(); } + /** + * Configure the credentials provider + */ default Builder credentialsProvider(IdentityProvider credentialsProvider) { throw new UnsupportedOperationException(); } @@ -116,6 +134,20 @@ default IdentityProvider credentialsProvider() throw new UnsupportedOperationException(); } + /** + * Adds the given auth scheme. Replaces the an existing auth scheme with the same id. + */ + default Builder putAuthScheme(AuthScheme authScheme) { + throw new UnsupportedOperationException(); + } + + /** + * Returns the configured map of auth schemes. + */ + default Map> authSchemes() { + throw new UnsupportedOperationException(); + } + @Override AwsServiceClientConfiguration build(); } @@ -126,8 +158,10 @@ protected abstract static class BuilderImpl implements Builder { protected URI endpointOverride; protected EndpointProvider endpointProvider; protected IdentityProvider credentialsProvider; + protected Map> authSchemes; protected BuilderImpl() { + } protected BuilderImpl(AwsServiceClientConfiguration awsServiceClientConfiguration) { @@ -167,6 +201,22 @@ public final Builder credentialsProvider(IdentityProvider credentialsProvider() { return credentialsProvider; } - } + @Override + public final Builder putAuthScheme(AuthScheme authScheme) { + if (authSchemes == null) { + authSchemes = new HashMap<>(); + } + authSchemes.put(authScheme.schemeId(), authScheme); + return this; + } + + @Override + public final Map> authSchemes() { + if (authSchemes == null) { + return Collections.emptyMap(); + } + return Collections.unmodifiableMap(new HashMap<>(authSchemes)); + } + } }