• 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.core.interceptor;
17 
18 import java.io.BufferedReader;
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.io.InputStreamReader;
22 import java.net.URL;
23 import java.nio.charset.StandardCharsets;
24 import java.util.ArrayList;
25 import java.util.Collection;
26 import java.util.Collections;
27 import java.util.Enumeration;
28 import java.util.List;
29 import java.util.stream.Collectors;
30 import java.util.stream.Stream;
31 import software.amazon.awssdk.annotations.SdkProtectedApi;
32 import software.amazon.awssdk.core.exception.SdkClientException;
33 import software.amazon.awssdk.core.internal.util.ClassLoaderHelper;
34 import software.amazon.awssdk.utils.Validate;
35 
36 /**
37  * Factory for creating request/response handler chains from the classpath.
38  */
39 @SdkProtectedApi
40 public final class ClasspathInterceptorChainFactory {
41 
42     private static final String GLOBAL_INTERCEPTOR_PATH = "software/amazon/awssdk/global/handlers/execution.interceptors";
43 
44     /**
45      * Constructs a new request handler chain by analyzing the specified classpath resource.
46      *
47      * @param resource The resource to load from the classpath containing the list of request handlers to instantiate.
48      * @return A list of request handlers based on the handlers referenced in the specified resource.
49      */
getInterceptors(String resource)50     public List<ExecutionInterceptor> getInterceptors(String resource) {
51         return new ArrayList<>(createExecutionInterceptorsFromClasspath(resource));
52     }
53 
54     /**
55      * Load the global handlers by reading the global execution interceptors resource.
56      */
getGlobalInterceptors()57     public List<ExecutionInterceptor> getGlobalInterceptors() {
58         return new ArrayList<>(createExecutionInterceptorsFromClasspath(GLOBAL_INTERCEPTOR_PATH));
59     }
60 
createExecutionInterceptorsFromClasspath(String path)61     private Collection<ExecutionInterceptor> createExecutionInterceptorsFromClasspath(String path) {
62         try {
63             return createExecutionInterceptorsFromResources(classLoader().getResources(path))
64                 .collect(Collectors.toMap(p -> p.getClass().getSimpleName(), p -> p, (p1, p2) -> p1)).values();
65         } catch (IOException e) {
66             throw SdkClientException.builder()
67                                     .message("Unable to instantiate execution interceptor chain.")
68                                     .cause(e)
69                                     .build();
70         }
71     }
72 
createExecutionInterceptorsFromResources(Enumeration<URL> resources)73     private Stream<ExecutionInterceptor> createExecutionInterceptorsFromResources(Enumeration<URL> resources) {
74         if (resources == null) {
75             return Stream.empty();
76         }
77 
78         return Collections.list(resources).stream().flatMap(this::createExecutionInterceptorFromResource);
79     }
80 
createExecutionInterceptorFromResource(URL resource)81     private Stream<ExecutionInterceptor> createExecutionInterceptorFromResource(URL resource) {
82         try {
83             if (resource == null) {
84                 return Stream.empty();
85             }
86 
87             List<ExecutionInterceptor> interceptors = new ArrayList<>();
88 
89             try (InputStream stream = resource.openStream();
90                  InputStreamReader streamReader = new InputStreamReader(stream, StandardCharsets.UTF_8);
91                  BufferedReader fileReader = new BufferedReader(streamReader)) {
92 
93                 String interceptorClassName = fileReader.readLine();
94                 while (interceptorClassName != null) {
95                     ExecutionInterceptor interceptor = createExecutionInterceptor(interceptorClassName);
96                     if (interceptor != null) {
97                         interceptors.add(interceptor);
98                     }
99                     interceptorClassName = fileReader.readLine();
100                 }
101             }
102 
103             return interceptors.stream();
104         } catch (IOException e) {
105             throw SdkClientException.builder()
106                                     .message("Unable to instantiate execution interceptor chain.")
107                                     .cause(e)
108                                     .build();
109         }
110     }
111 
createExecutionInterceptor(String interceptorClassName)112     private ExecutionInterceptor createExecutionInterceptor(String interceptorClassName) {
113         if (interceptorClassName == null) {
114             return null;
115         }
116 
117         interceptorClassName = interceptorClassName.trim();
118         if (interceptorClassName.equals("")) {
119             return null;
120         }
121 
122         try {
123             Class<?> executionInterceptorClass = ClassLoaderHelper.loadClass(interceptorClassName,
124                                                                              ExecutionInterceptor.class, getClass());
125             Object executionInterceptorObject = executionInterceptorClass.newInstance();
126 
127             if (executionInterceptorObject instanceof ExecutionInterceptor) {
128                 return (ExecutionInterceptor) executionInterceptorObject;
129             } else {
130                 throw SdkClientException.builder()
131                                         .message("Unable to instantiate request handler chain for client. Listed"
132                                                 + " request handler ('" + interceptorClassName + "') does not implement" +
133                                                 " the " + ExecutionInterceptor.class + " API.")
134                                         .build();
135             }
136         } catch (IllegalAccessException | ClassNotFoundException | InstantiationException e) {
137             throw SdkClientException.builder()
138                                     .message("Unable to instantiate executor interceptor for client.")
139                                     .cause(e)
140                                     .build();
141         }
142     }
143 
classLoader()144     private ClassLoader classLoader() {
145         return Validate.notNull(ClassLoaderHelper.classLoader(getClass()),
146                                 "Failed to load the classloader of this class or the system.");
147     }
148 }
149