1
15 package com.amazonaws.internal.config;
16
17 import java.io.IOException;
18 import java.net.URL;
19 import java.util.Collections;
20 import java.util.HashMap;
21 import java.util.LinkedList;
22 import java.util.List;
23 import java.util.Map;
24
25 import com.amazonaws.annotation.Immutable;
26 import com.amazonaws.log.InternalLogApi;
27 import com.amazonaws.log.InternalLogFactory;
28 import com.amazonaws.util.ClassLoaderHelper;
29 import com.fasterxml.jackson.core.JsonParseException;
30 import com.fasterxml.jackson.core.JsonParser;
31 import com.fasterxml.jackson.databind.DeserializationFeature;
32 import com.fasterxml.jackson.databind.JsonMappingException;
33 import com.fasterxml.jackson.databind.MapperFeature;
34 import com.fasterxml.jackson.databind.ObjectMapper;
35
36
39 @Immutable
40 public class InternalConfig {
41
42
43 private static final ObjectMapper MAPPER = new ObjectMapper()
44 .disable(MapperFeature.CAN_OVERRIDE_ACCESS_MODIFIERS)
45 .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
46 .configure(JsonParser.Feature.ALLOW_COMMENTS, true);
47
48
49 private static final InternalLogApi log = InternalLogFactory.getLog(InternalConfig.class);
50
51 static final String DEFAULT_CONFIG_RESOURCE_RELATIVE_PATH = "awssdk_config_default.json";
52 static final String DEFAULT_CONFIG_RESOURCE_ABSOLUTE_PATH = "/com/amazonaws/internal/config/"
53 + DEFAULT_CONFIG_RESOURCE_RELATIVE_PATH;
54
55 static final String CONFIG_OVERRIDE_RESOURCE = "awssdk_config_override.json";
56
57 static final String ENDPOINT_DISCOVERY_CONFIG_ABSOLUTE_PATH =
58 "/com/amazonaws/endpointdiscovery/endpoint-discovery.json";
59
60 private static final String SERVICE_REGION_DELIMITOR = "/";
61
62 private final SignerConfig defaultSignerConfig;
63 private final Map<String, SignerConfig> serviceRegionSigners;
64 private final Map<String, SignerConfig> regionSigners;
65 private final Map<String, SignerConfig> serviceSigners;
66 private final Map<String, HttpClientConfig> httpClients;
67
68 private final List<HostRegexToRegionMapping> hostRegexToRegionMappings;
69
70 private final String userAgentTemplate;
71
72 private final boolean endpointDiscoveryEnabled;
73
74
80 InternalConfig(InternalConfigJsonHelper defaults,
81 InternalConfigJsonHelper override,
82 EndpointDiscoveryConfig endpointDiscoveryConfig) {
83 SignerConfigJsonHelper scb = defaults.getDefaultSigner();
84 this.defaultSignerConfig = scb == null ? null : scb.build();
85
86 regionSigners = mergeSignerMap(defaults.getRegionSigners(), override.getRegionSigners(), "region");
87 serviceSigners = mergeSignerMap(defaults.getServiceSigners(), override.getServiceSigners(), "service");
88 serviceRegionSigners = mergeSignerMap(defaults.getServiceRegionSigners(), override.getServiceRegionSigners(),
89 "service" + SERVICE_REGION_DELIMITOR + "region");
90 httpClients = merge(defaults.getHttpClients(), override.getHttpClients());
91
92 hostRegexToRegionMappings = append(override.getHostRegexToRegionMappings(),
93 defaults.getHostRegexToRegionMappings());
94
95 if (override.getUserAgentTemplate() != null) {
96 userAgentTemplate = override.getUserAgentTemplate();
97 } else {
98 userAgentTemplate = defaults.getUserAgentTemplate();
99 }
100
101 endpointDiscoveryEnabled = endpointDiscoveryConfig.isEndpointDiscoveryEnabled();
102 }
103
104
115 private Map<String, SignerConfig> mergeSignerMap(JsonIndex<SignerConfigJsonHelper, SignerConfig>[] defaults,
116 JsonIndex<SignerConfigJsonHelper, SignerConfig>[] overrides,
117 String theme) {
118 Map<String, SignerConfig> map = buildSignerMap(defaults, theme);
119 Map<String, SignerConfig> mapOverride = buildSignerMap(overrides, theme);
120 map.putAll(mapOverride);
121 return Collections.unmodifiableMap(map);
122 }
123
124 private <C extends Builder<T>, T> Map<String, T> merge(JsonIndex<C, T>[] defaults, JsonIndex<C, T>[] overrides) {
125 Map<String, T> map = buildMap(defaults);
126 Map<String, T> mapOverride = buildMap(overrides);
127 map.putAll(mapOverride);
128 return Collections.unmodifiableMap(map);
129 }
130
131 private <C extends Builder<T>, T> Map<String, T> buildMap(JsonIndex<C, T>[] signerIndexes) {
132 Map<String, T> map = new HashMap<String, T>();
133 if (signerIndexes != null) {
134 for (JsonIndex<C, T> index : signerIndexes) {
135 String region = index.getKey();
136 T prev = map.put(region, index.newReadOnlyConfig());
137 if (prev != null) {
138 log.warn("Duplicate definition of signer for " + index.getKey());
139 }
140 }
141 }
142 return map;
143 }
144
145 private <C extends Builder<T>, T> List<T> append(C[] defaults, C[] overrides) {
146 List<T> list = new LinkedList<T>();
147 if (defaults != null) {
148 for (C builder : defaults) {
149 list.add(builder.build());
150 }
151 }
152 if (overrides != null) {
153 for (C builder : overrides) {
154 list.add(builder.build());
155 }
156 }
157 return list;
158 }
159
160
168 private Map<String, SignerConfig> buildSignerMap(JsonIndex<SignerConfigJsonHelper, SignerConfig>[] signerIndexes,
169 String theme) {
170 Map<String, SignerConfig> map = new HashMap<String, SignerConfig>();
171 if (signerIndexes != null) {
172 for (JsonIndex<SignerConfigJsonHelper, SignerConfig> index : signerIndexes) {
173 String region = index.getKey();
174 SignerConfig prev = map.put(region, index.newReadOnlyConfig());
175 if (prev != null) {
176 log.warn("Duplicate definition of signer for " + theme + " " + index.getKey());
177 }
178 }
179 }
180 return map;
181 }
182
183
186 public SignerConfig getSignerConfig(String serviceName) {
187 return getSignerConfig(serviceName, null);
188 }
189
190
193 public HttpClientConfig getHttpClientConfig(String httpClientName) {
194 return httpClients.get(httpClientName);
195 }
196
197
206 public SignerConfig getSignerConfig(String serviceName, String regionName) {
207 if (serviceName == null)
208 throw new IllegalArgumentException();
209 SignerConfig signerConfig = null;
210 if (regionName != null) {
211
212 String key = serviceName + SERVICE_REGION_DELIMITOR + regionName;
213 signerConfig = serviceRegionSigners.get(key);
214 if (signerConfig != null) {
215 return signerConfig;
216 }
217
218 signerConfig = regionSigners.get(regionName);
219 if (signerConfig != null) {
220 return signerConfig;
221 }
222 }
223
224 signerConfig = serviceSigners.get(serviceName);
225
226 return signerConfig == null ? defaultSignerConfig : signerConfig;
227 }
228
229
232 public List<HostRegexToRegionMapping> getHostRegexToRegionMappings() {
233 return Collections.unmodifiableList(hostRegexToRegionMappings);
234 }
235
236
239 public String getUserAgentTemplate() {
240 return userAgentTemplate;
241 }
242
243 public boolean endpointDiscoveryEnabled() {
244 return endpointDiscoveryEnabled;
245 }
246
247 static <T> T loadfrom(URL url, Class<T> clazz) throws JsonParseException, JsonMappingException, IOException {
248 if (url == null)
249 throw new IllegalArgumentException();
250 T target = MAPPER.readValue(url, clazz);
251 return target;
252 }
253
254
257 static InternalConfig load() throws JsonParseException, JsonMappingException, IOException {
258 URL configUrl = getResource(DEFAULT_CONFIG_RESOURCE_RELATIVE_PATH, true, false);
259 if (configUrl == null) {
260 configUrl = getResource(DEFAULT_CONFIG_RESOURCE_ABSOLUTE_PATH, false, false);
261 }
262
263 InternalConfigJsonHelper config = loadfrom(configUrl, InternalConfigJsonHelper.class);
264 InternalConfigJsonHelper configOverride;
265
266 URL overrideUrl = getResource(CONFIG_OVERRIDE_RESOURCE, false, true);
267 if (overrideUrl == null) {
268 overrideUrl = getResource(CONFIG_OVERRIDE_RESOURCE, false, false);
269 }
270 if (overrideUrl == null) {
271 log.debug("Configuration override " + CONFIG_OVERRIDE_RESOURCE + " not found.");
272 configOverride = new InternalConfigJsonHelper();
273 } else {
274 configOverride = loadfrom(overrideUrl, InternalConfigJsonHelper.class);
275 }
276
277 EndpointDiscoveryConfig endpointDiscoveryConfig = new EndpointDiscoveryConfig();
278
279 URL endpointDiscoveryConfigUrl = getResource(ENDPOINT_DISCOVERY_CONFIG_ABSOLUTE_PATH, false, false);
280
281 if (endpointDiscoveryConfigUrl != null) {
282 endpointDiscoveryConfig = loadfrom(endpointDiscoveryConfigUrl, EndpointDiscoveryConfig.class);
283 }
284
285 InternalConfig merged = new InternalConfig(config, configOverride, endpointDiscoveryConfig);
286 merged.setDefaultConfigFileLocation(configUrl);
287 merged.setOverrideConfigFileLocation(overrideUrl);
288 return merged;
289 }
290
291 private static URL getResource(String path, boolean classesFirst, boolean addLeadingSlash) {
292 path = addLeadingSlash ? "/" + path : path;
293
294 URL resourceUrl = ClassLoaderHelper.getResource(path, classesFirst, InternalConfig.class);
295
296 return resourceUrl;
297 }
298
299
302
303 private URL defaultConfigFileLocation;
304 private URL overrideConfigFileLocation;
305
306 public URL getDefaultConfigFileLocation() {
307 return defaultConfigFileLocation;
308 }
309
310 public URL getOverrideConfigFileLocation() {
311 return overrideConfigFileLocation;
312 }
313
314 void setDefaultConfigFileLocation(URL url) {
315 this.defaultConfigFileLocation = url;
316 }
317
318 void setOverrideConfigFileLocation(URL url) {
319 this.overrideConfigFileLocation = url;
320 }
321
322 void dump() {
323 StringBuilder sb = new StringBuilder().append("defaultSignerConfig: ").append(defaultSignerConfig).append("\n")
324 .append("serviceRegionSigners: ").append(serviceRegionSigners).append("\n").append("regionSigners: ")
325 .append(regionSigners).append("\n").append("serviceSigners: ").append(serviceSigners).append("\n")
326 .append("userAgentTemplate: ").append(userAgentTemplate);
327 log.debug(sb.toString());
328 }
329
330 public static class Factory {
331 private static final InternalConfig SINGELTON;
332
333 static {
334 InternalConfig config = null;
335 try {
336 config = InternalConfig.load();
337 } catch (RuntimeException ex) {
338 throw ex;
339 } catch (Exception ex) {
340 throw new IllegalStateException("Fatal: Failed to load the internal config for AWS Java SDK", ex);
341 }
342 SINGELTON = config;
343 }
344
345
348 public static InternalConfig getInternalConfig() {
349 return SINGELTON;
350 }
351 }
352 }
353