1 /* 2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"). 5 * You may not use this file except in compliance with the License. 6 * A copy of the License is located at 7 * 8 * http://aws.amazon.com/apache2.0 9 * 10 * or in the "license" file accompanying this file. This file is distributed 11 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 * express or implied. See the License for the specific language governing 13 * permissions and limitations under the License. 14 */ 15 16 package software.amazon.awssdk.core.client.config; 17 18 import static software.amazon.awssdk.core.client.config.SdkClientOption.ENDPOINT_OVERRIDDEN; 19 import static software.amazon.awssdk.core.client.config.SdkClientOption.SIGNER_OVERRIDDEN; 20 21 import java.util.Map; 22 import java.util.function.Consumer; 23 import java.util.function.Supplier; 24 import software.amazon.awssdk.annotations.SdkProtectedApi; 25 import software.amazon.awssdk.core.internal.SdkInternalTestAdvancedClientOption; 26 import software.amazon.awssdk.core.signer.Signer; 27 import software.amazon.awssdk.utils.AttributeMap; 28 import software.amazon.awssdk.utils.SdkAutoCloseable; 29 import software.amazon.awssdk.utils.ToString; 30 import software.amazon.awssdk.utils.builder.CopyableBuilder; 31 import software.amazon.awssdk.utils.builder.ToCopyableBuilder; 32 33 /** 34 * A collection of configuration that is required by an AWS client in order to operate. 35 * 36 * Configuration can be set via {@link SdkClientConfiguration.Builder#option(ClientOption, Object)} and checked via 37 * {@link SdkClientConfiguration#option(ClientOption)}. 38 * 39 * This configuration can be merged with other configuration using {@link SdkClientConfiguration#merge}. 40 * 41 * This configuration object can be {@link #close()}d to release all closeable resources configured within it. 42 */ 43 @SdkProtectedApi 44 public final class SdkClientConfiguration 45 implements ToCopyableBuilder<SdkClientConfiguration.Builder, SdkClientConfiguration>, SdkAutoCloseable { 46 private final AttributeMap attributes; 47 SdkClientConfiguration(AttributeMap attributes)48 private SdkClientConfiguration(AttributeMap attributes) { 49 this.attributes = attributes; 50 } 51 52 /** 53 * Create a builder for a {@link SdkClientConfiguration}. 54 */ builder()55 public static SdkClientConfiguration.Builder builder() { 56 return new Builder(AttributeMap.builder()); 57 } 58 59 /** 60 * Create a {@link SdkClientConfiguration} from the provided {@link ClientOverrideConfiguration}. This copies the 61 * properties out of the configuration and ensures that _OVERRIDDEN properties are properly set, like 62 * {@link SdkClientOption#SIGNER_OVERRIDDEN}. 63 */ fromOverrideConfiguration(ClientOverrideConfiguration configuration)64 public static SdkClientConfiguration fromOverrideConfiguration(ClientOverrideConfiguration configuration) { 65 SdkClientConfiguration result = configuration.asSdkClientConfiguration(); 66 67 Boolean endpointOverriddenOverride = result.option(SdkInternalTestAdvancedClientOption.ENDPOINT_OVERRIDDEN_OVERRIDE); 68 Signer signerFromOverride = result.option(SdkAdvancedClientOption.SIGNER); 69 70 if (endpointOverriddenOverride == null && signerFromOverride == null) { 71 return result; 72 } 73 74 SdkClientConfiguration.Builder resultBuilder = result.toBuilder(); 75 if (signerFromOverride != null) { 76 resultBuilder.option(SIGNER_OVERRIDDEN, true); 77 } 78 if (endpointOverriddenOverride != null) { 79 resultBuilder.option(ENDPOINT_OVERRIDDEN, endpointOverriddenOverride); 80 } 81 return resultBuilder.build(); 82 } 83 84 /** 85 * Retrieve the value of a specific option. 86 */ option(ClientOption<T> option)87 public <T> T option(ClientOption<T> option) { 88 return attributes.get(option); 89 } 90 91 /** 92 * Create a {@link ClientOverrideConfiguration} using the values currently in this configuration. 93 */ asOverrideConfiguration()94 public ClientOverrideConfiguration asOverrideConfiguration() { 95 return new ClientOverrideConfiguration.DefaultBuilder(toBuilder()).build(); 96 } 97 98 /** 99 * Merge this configuration with another configuration, where this configuration's values take precedence. 100 */ merge(SdkClientConfiguration configuration)101 public SdkClientConfiguration merge(SdkClientConfiguration configuration) { 102 return new SdkClientConfiguration(attributes.merge(configuration.attributes)); 103 } 104 merge(Consumer<SdkClientConfiguration.Builder> configuration)105 public SdkClientConfiguration merge(Consumer<SdkClientConfiguration.Builder> configuration) { 106 return merge(builder().applyMutation(configuration).build()); 107 } 108 109 @Override toString()110 public String toString() { 111 return ToString.builder("SdkClientConfiguration") 112 .add("attributes", attributes) 113 .build(); 114 } 115 116 @Override toBuilder()117 public Builder toBuilder() { 118 return new Builder(attributes.toBuilder()); 119 } 120 121 /** 122 * Close this configuration, which closes all closeable attributes. 123 */ 124 @Override close()125 public void close() { 126 attributes.close(); 127 } 128 129 @Override equals(Object o)130 public boolean equals(Object o) { 131 if (this == o) { 132 return true; 133 } 134 if (o == null || getClass() != o.getClass()) { 135 return false; 136 } 137 138 SdkClientConfiguration that = (SdkClientConfiguration) o; 139 140 return attributes.equals(that.attributes); 141 } 142 143 @Override hashCode()144 public int hashCode() { 145 return attributes.hashCode(); 146 } 147 148 public static final class Builder implements CopyableBuilder<Builder, SdkClientConfiguration> { 149 private final AttributeMap.Builder attributes; 150 Builder(AttributeMap.Builder attributes)151 private Builder(AttributeMap.Builder attributes) { 152 this.attributes = attributes; 153 } 154 155 /** 156 * Create a {@link ClientOverrideConfiguration.Builder} using the values currently in this builder. 157 */ asOverrideConfigurationBuilder()158 public ClientOverrideConfiguration.Builder asOverrideConfigurationBuilder() { 159 return new ClientOverrideConfiguration.DefaultBuilder(this); 160 } 161 162 /** 163 * Configure the value of a specific option. 164 */ option(ClientOption<T> option, T value)165 public <T> Builder option(ClientOption<T> option, T value) { 166 this.attributes.put(option, value); 167 return this; 168 } 169 170 /** 171 * Add a mapping between the provided option and value provider. 172 * 173 * The lazy value will only be resolved when the value is needed. During resolution, the lazy value is provided with a 174 * value reader. The value reader will fail if the reader attempts to read its own value (directly, or indirectly 175 * through other lazy values). 176 * 177 * If a value is updated that a lazy value is depended on, the lazy value will be re-resolved the next time the lazy 178 * value is accessed. 179 */ lazyOption(ClientOption<T> option, AttributeMap.LazyValue<T> lazyValue)180 public <T> Builder lazyOption(ClientOption<T> option, AttributeMap.LazyValue<T> lazyValue) { 181 this.attributes.putLazy(option, lazyValue); 182 return this; 183 } 184 185 /** 186 * Equivalent to {@link #lazyOption(ClientOption, AttributeMap.LazyValue)}, but does not assign the value if there is 187 * already a non-null value assigned for the provided option. 188 */ lazyOptionIfAbsent(ClientOption<T> option, AttributeMap.LazyValue<T> lazyValue)189 public <T> Builder lazyOptionIfAbsent(ClientOption<T> option, AttributeMap.LazyValue<T> lazyValue) { 190 this.attributes.putLazyIfAbsent(option, lazyValue); 191 return this; 192 } 193 194 /** 195 * Retrieve the value of a specific option. 196 */ option(ClientOption<T> option)197 public <T> T option(ClientOption<T> option) { 198 return this.attributes.get(option); 199 } 200 201 /** 202 * Add a mapping between the provided key and value, if the current value for the option is null. Returns the value. 203 */ computeOptionIfAbsent(ClientOption<T> option, Supplier<T> valueSupplier)204 public <T> T computeOptionIfAbsent(ClientOption<T> option, Supplier<T> valueSupplier) { 205 return this.attributes.computeIfAbsent(option, valueSupplier); 206 } 207 208 /** 209 * Adds all the options from the map provided. This is not type safe, and will throw an exception during creation if 210 * a value in the map is not of the correct type for its option. 211 */ putAll(Map<? extends ClientOption<?>, ?> options)212 public Builder putAll(Map<? extends ClientOption<?>, ?> options) { 213 this.attributes.putAll(options); 214 return this; 215 } 216 217 /** 218 * Put all of the attributes from the provided override configuration into this one. 219 */ putAll(ClientOverrideConfiguration configuration)220 public Builder putAll(ClientOverrideConfiguration configuration) { 221 this.attributes.putAll(fromOverrideConfiguration(configuration).attributes); 222 return this; 223 } 224 225 @Override copy()226 public Builder copy() { 227 return new Builder(attributes.copy()); 228 } 229 230 @Override build()231 public SdkClientConfiguration build() { 232 return new SdkClientConfiguration(attributes.build()); 233 } 234 } 235 } 236