1 /*
2  * Copyright 2013-2020 the original author or authors.
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  * You may obtain a copy of the License at
7  *
8  *      https://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.springframework.cloud.aws.core.config;
18
19 import java.lang.reflect.Method;
20 import java.util.concurrent.ExecutorService;
21
22 import com.amazonaws.AmazonWebServiceClient;
23 import com.amazonaws.auth.AWSCredentialsProvider;
24 import com.amazonaws.client.builder.AwsAsyncClientBuilder;
25 import com.amazonaws.client.builder.AwsClientBuilder;
26 import com.amazonaws.client.builder.ExecutorFactory;
27 import com.amazonaws.regions.Region;
28 import com.amazonaws.regions.RegionUtils;
29 import com.amazonaws.regions.Regions;
30
31 import org.springframework.beans.factory.config.AbstractFactoryBean;
32 import org.springframework.cloud.aws.core.SpringCloudClientConfiguration;
33 import org.springframework.cloud.aws.core.region.RegionProvider;
34 import org.springframework.util.Assert;
35 import org.springframework.util.ClassUtils;
36 import org.springframework.util.ReflectionUtils;
37
38 /**
39  * {@link org.springframework.beans.factory.FactoryBean} class to create
40  * {@link AmazonWebServiceClient} instances. This class is responsible to create the
41  * respective AmazonWebServiceClient classes because the configuration through Springs's
42  * BeanFactory fails due to invalid properties inside the Webservice client classes (see
43  * https://github.com/aws/aws-sdk-java/issues/325)
44  *
45  * @param <T> implementation of the {@link AmazonWebServiceClient}
46  * @author Agim Emruli
47  * @author EddĂș MelĂ©ndez
48  */

49 public class AmazonWebserviceClientFactoryBean<T extends AmazonWebServiceClient>
50         extends AbstractFactoryBean<T> {
51
52     private final Class<? extends AmazonWebServiceClient> clientClass;
53
54     private final AWSCredentialsProvider credentialsProvider;
55
56     private RegionProvider regionProvider;
57
58     private Region customRegion;
59
60     private ExecutorService executor;
61
62     public AmazonWebserviceClientFactoryBean(Class<T> clientClass,
63             AWSCredentialsProvider credentialsProvider) {
64         this.clientClass = clientClass;
65         this.credentialsProvider = credentialsProvider;
66     }
67
68     public AmazonWebserviceClientFactoryBean(Class<T> clientClass,
69             AWSCredentialsProvider credentialsProvider, RegionProvider regionProvider) {
70         this(clientClass, credentialsProvider);
71         setRegionProvider(regionProvider);
72     }
73
74     @Override
75     public Class<?> getObjectType() {
76         return this.clientClass;
77     }
78
79     @SuppressWarnings("unchecked")
80     @Override
81     protected T createInstance() throws Exception {
82
83         String builderName = this.clientClass.getName() + "Builder";
84         Class<?> className = ClassUtils.resolveClassName(builderName,
85                 ClassUtils.getDefaultClassLoader());
86
87         Method method = ClassUtils.getStaticMethod(className, "standard");
88         Assert.notNull(method, "Could not find standard() method in class:'"
89                 + className.getName() + "'");
90
91         AwsClientBuilder<?, T> builder = (AwsClientBuilder<?, T>) ReflectionUtils
92                 .invokeMethod(method, null);
93
94         if (this.executor != null) {
95             AwsAsyncClientBuilder<?, T> asyncBuilder = (AwsAsyncClientBuilder<?, T>) builder;
96             asyncBuilder.withExecutorFactory((ExecutorFactory) () -> this.executor);
97         }
98
99         builder.withClientConfiguration(
100                 SpringCloudClientConfiguration.getClientConfiguration());
101
102         if (this.credentialsProvider != null) {
103             builder.withCredentials(this.credentialsProvider);
104         }
105
106         if (this.customRegion != null) {
107             builder.withRegion(this.customRegion.getName());
108         }
109         else if (this.regionProvider != null) {
110             builder.withRegion(this.regionProvider.getRegion().getName());
111         }
112         else {
113             builder.withRegion(Regions.DEFAULT_REGION);
114         }
115         return builder.build();
116     }
117
118     public void setRegionProvider(RegionProvider regionProvider) {
119         this.regionProvider = regionProvider;
120     }
121
122     public void setCustomRegion(String customRegionName) {
123         this.customRegion = RegionUtils.getRegion(customRegionName);
124     }
125
126     public void setExecutor(ExecutorService executor) {
127         this.executor = executor;
128     }
129
130     @Override
131     protected void destroyInstance(T instance) throws Exception {
132         instance.shutdown();
133     }
134
135 }
136