• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.awscore.endpoint;
17 
18 import java.net.URI;
19 import java.net.URISyntaxException;
20 import java.util.ArrayList;
21 import java.util.HashMap;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.function.Supplier;
25 import software.amazon.awssdk.annotations.NotThreadSafe;
26 import software.amazon.awssdk.annotations.SdkProtectedApi;
27 import software.amazon.awssdk.core.exception.SdkClientException;
28 import software.amazon.awssdk.profiles.ProfileFile;
29 import software.amazon.awssdk.profiles.ProfileFileSystemSetting;
30 import software.amazon.awssdk.regions.EndpointTag;
31 import software.amazon.awssdk.regions.Region;
32 import software.amazon.awssdk.regions.ServiceEndpointKey;
33 import software.amazon.awssdk.regions.ServiceMetadata;
34 import software.amazon.awssdk.regions.ServiceMetadataAdvancedOption;
35 import software.amazon.awssdk.utils.Lazy;
36 import software.amazon.awssdk.utils.Validate;
37 
38 /**
39  * Uses service metadata and the request region to construct an endpoint for a specific service
40  */
41 @NotThreadSafe
42 @SdkProtectedApi
43 // TODO We may not need this anymore, we should default to AWS partition when resolving
44 // a region we don't know about yet.
45 public final class DefaultServiceEndpointBuilder {
46     private final String serviceName;
47     private final String protocol;
48 
49     private Region region;
50     private Supplier<ProfileFile> profileFile;
51     private String profileName;
52     private final Map<ServiceMetadataAdvancedOption<?>, Object> advancedOptions = new HashMap<>();
53     private Boolean dualstackEnabled;
54     private Boolean fipsEnabled;
55 
DefaultServiceEndpointBuilder(String serviceName, String protocol)56     public DefaultServiceEndpointBuilder(String serviceName, String protocol) {
57         this.serviceName = Validate.paramNotNull(serviceName, "serviceName");
58         this.protocol = Validate.paramNotNull(protocol, "protocol");
59     }
60 
withRegion(Region region)61     public DefaultServiceEndpointBuilder withRegion(Region region) {
62         if (region == null) {
63             throw new IllegalArgumentException("Region cannot be null");
64         }
65         this.region = region;
66         return this;
67     }
68 
withProfileFile(Supplier<ProfileFile> profileFile)69     public DefaultServiceEndpointBuilder withProfileFile(Supplier<ProfileFile> profileFile) {
70         this.profileFile = profileFile;
71         return this;
72     }
73 
withProfileFile(ProfileFile profileFile)74     public DefaultServiceEndpointBuilder withProfileFile(ProfileFile profileFile) {
75         this.profileFile = () -> profileFile;
76         return this;
77     }
78 
withProfileName(String profileName)79     public DefaultServiceEndpointBuilder withProfileName(String profileName) {
80         this.profileName = profileName;
81         return this;
82     }
83 
putAdvancedOption(ServiceMetadataAdvancedOption<T> option, T value)84     public <T> DefaultServiceEndpointBuilder putAdvancedOption(ServiceMetadataAdvancedOption<T> option, T value) {
85         advancedOptions.put(option, value);
86         return this;
87     }
88 
withDualstackEnabled(Boolean dualstackEnabled)89     public DefaultServiceEndpointBuilder withDualstackEnabled(Boolean dualstackEnabled) {
90         this.dualstackEnabled = dualstackEnabled;
91         return this;
92     }
93 
withFipsEnabled(Boolean fipsEnabled)94     public DefaultServiceEndpointBuilder withFipsEnabled(Boolean fipsEnabled) {
95         this.fipsEnabled = fipsEnabled;
96         return this;
97     }
98 
getServiceEndpoint()99     public URI getServiceEndpoint() {
100         if (profileFile == null) {
101             profileFile = new Lazy<>(ProfileFile::defaultProfileFile)::getValue;
102         }
103 
104         if (profileName == null) {
105             profileName = ProfileFileSystemSetting.AWS_PROFILE.getStringValueOrThrow();
106         }
107 
108         if (dualstackEnabled == null) {
109             dualstackEnabled = DualstackEnabledProvider.builder()
110                                                        .profileFile(profileFile)
111                                                        .profileName(profileName)
112                                                        .build()
113                                                        .isDualstackEnabled()
114                                                        .orElse(false);
115         }
116 
117         if (fipsEnabled == null) {
118             fipsEnabled = FipsEnabledProvider.builder()
119                                              .profileFile(profileFile)
120                                              .profileName(profileName)
121                                              .build()
122                                              .isFipsEnabled()
123                                              .orElse(false);
124         }
125 
126 
127 
128         List<EndpointTag> endpointTags = new ArrayList<>();
129         if (dualstackEnabled) {
130             endpointTags.add(EndpointTag.DUALSTACK);
131         }
132         if (fipsEnabled) {
133             endpointTags.add(EndpointTag.FIPS);
134         }
135 
136         ServiceMetadata serviceMetadata = ServiceMetadata.of(serviceName)
137                                                          .reconfigure(c -> c.profileFile(profileFile)
138                                                                             .profileName(profileName)
139                                                                             .advancedOptions(advancedOptions));
140         URI endpoint = addProtocolToServiceEndpoint(serviceMetadata.endpointFor(ServiceEndpointKey.builder()
141                                                                                                   .region(region)
142                                                                                                   .tags(endpointTags)
143                                                                                                   .build()));
144 
145         if (endpoint.getHost() == null) {
146             String error = "Configured region (" + region + ") and tags (" + endpointTags + ") resulted in an invalid URI: "
147                            + endpoint + ". This is usually caused by an invalid region configuration.";
148 
149             List<Region> exampleRegions = serviceMetadata.regions();
150             if (!exampleRegions.isEmpty()) {
151                 error += " Valid regions: " + exampleRegions;
152             }
153 
154             throw SdkClientException.create(error);
155         }
156 
157         return endpoint;
158     }
159 
addProtocolToServiceEndpoint(URI endpointWithoutProtocol)160     private URI addProtocolToServiceEndpoint(URI endpointWithoutProtocol) throws IllegalArgumentException {
161         try {
162             return new URI(protocol + "://" + endpointWithoutProtocol);
163         } catch (URISyntaxException e) {
164             throw new IllegalArgumentException(e);
165         }
166     }
167 
getRegion()168     public Region getRegion() {
169         return region;
170     }
171 }
172